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

102.网络游戏逆向分析与漏洞攻防-ui界面的设计-反隐身功能的界面设计与实现(有不使用MFC生成,自己手写代码创建复选框与事件的例子)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

如果看不懂、不知道现在做的什么,那就跟着做完看效果,代码看不懂是正常的,只要会抄就行,抄着抄着就能懂了

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

上一个内容:101.怪物列表的界面与显示

码云版本号:25d6bc10c10a5df6ad3fe79cb92cd1e7d127ee57

代码下载地址,在 titan 目录下,文件名为:titan-反隐身功能的界面设计与实现.zip

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

提取码:q9n5

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

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

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

提取码:78h8

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

以 101.怪物列表的界面与显示 它的代码为基础进行修改

效果图:只是把界面搞了,对应的功能没有搞

这里先说一件事如果想实现自瞄,可以修改技能数据包中的目标坐标(94.利用数据包实现使用技能),把目标坐标换成对方角色的坐标就可以实现自瞄了,然后反隐身功能,游戏中专职

游戏中仲裁者到达10级后可以专职成执行者

执行者有一个技能可以隐身,反隐身功能就指的是,敌人使用隐身之后的技能我们也可以正常看到它

然后登陆我们可以抓包的客户端(今晚打老虎客户端是可以被抓包的)

然后使用隐身技能,然后查看今晚打老虎客户端抓到的包,下图是使用了隐身技能

然后找属性修改的数据包,然后就看到了下图的东西,Hide是隐藏的意思,Role是角色的意思,连起来就是角色隐身,这就很明显了

然后看一个解除隐身的数据包,解除隐身

解除隐身的方式是鼠标右击下图红框位置

然后看数据包,属性更新的数据包,因为角色是否显示这属于角色结构体里的属性,然后就看到了RoleHide=0,这说明RoleHide=0是显示RoleHide=1是不显示(隐身)

写代码测试

经过测试修改RoleHide属性是可以的

但是现在无法选中对方角色,选中这个操作是在服务端控制的,如果是在客户端控制的,可以通过逆向改(通过观察正常选择的数据包当做逆向的入口点),这种也不能选择,这种是违规操作,正常来说隐身了连看都看不到,更别说选了,如果选中了服务端可以用来认为客户端被搞了,然后进行封号,所以正常来说,如果选中的角色是隐身的,我要把选中隐身角色或违规选中时的发送的数据包给拦截下来这种的不能给服务端发

如果非要选中的话,如下图,可以给客户端伪造一个更新LastObject属性的数据包,LastObject的值就是角色id

然后到这就分析完了反隐身,接下来就给反隐身做一个界面

添加一个Dialog

然后给新加的Dialog改一下id(代码中会用到,最好与图中的名字保持一致)

然后它的属性

然后添加一个类

类名CWndSet

新加CWndSet.cpp文件

// CWndSet.cpp: 实现文件
//#include "pch.h"
#include "CWndSet.h"
#include "afxdialogex.h"
#include "resource.h"// CWndSet 对话框IMPLEMENT_DYNAMIC(CWndSet, CDialogEx)CWndSet::CWndSet(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_PAGE_2, pParent)
{
}CWndSet::~CWndSet()
{
}void CWndSet::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BOOL CWndSet::OnInitDialog()
{CDialogEx::OnInitDialog();for (int i = 0; i < (unsigned)SETNAME::MAX; i++) {int x = i % 15;int y = i / 15;// 创建一个按钮,按钮样式是 BS_CHECKBOX,也就是一个复选框setButton[i].Create(txtName[i], BS_CHECKBOX | WS_CHILD, CRect(y*110+10, x*30+5, y*110+110, x*30+35), this, IDC_SETBASE + i);// 设置字体setButton[i].SetFont(GetFont());// 显示按钮setButton[i].ShowWindow(TRUE);}return 0;
}// i的值是 OnInitDialog函数里写的 setButton[i].Create 里的 IDC_SETBASE + i
void CWndSet::OnSet(UINT i) {i = i - IDC_SETBASE;setButton[i].SetCheck(!setButton[i].GetCheck());
}
BEGIN_MESSAGE_MAP(CWndSet, CDialogEx)ON_CONTROL_RANGE(BN_CLICKED, IDC_SETBASE, IDC_SETBASE + (unsigned)SETNAME::MAX, OnSet)
END_MESSAGE_MAP()// CWndSet 消息处理程序

新加 CWndSet.h文件

#pragma once
#include "afxdialogex.h"
#include "CWndCreateRole.h"#define IDC_SETBASE (WM_USER + 100)// 处理按钮的消息映射
// CWndSet 对话框
enum class SETNAME {AntiHide, // 隐身AddSpeed, // 加速NeverFall, // 摔不死MAX
};
class CWndSet : public CDialogEx
{DECLARE_DYNAMIC(CWndSet)public:CWndSet(CWnd* pParent = nullptr);   // 标准构造函数virtual ~CWndSet();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_PAGE_2 };
#endifCString txtName[(unsigned)SETNAME::MAX]{L"反隐身",L"加速",L"摔不死",};CButton setButton[(unsigned)SETNAME::MAX];protected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持virtual BOOL OnInitDialog();DECLARE_MESSAGE_MAP()afx_msg void OnSet(UINT i);
};

CUI.cpp文件的修改:修改了 OnInitDialog函数

// CUI.cpp: 实现文件
//#include "pch.h"
#include "htdMfcDll.h"
#include "CUI.h"
#include "afxdialogex.h"
#include "extern_all.h"
// CUI 对话框IMPLEMENT_DYNAMIC(CUI, CDialogEx)CUI::CUI(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_MAIN, pParent), txtDetails(_T("")), txtChat(_T("")), txtChatName(_T(""))
{}CUI::~CUI()
{
}void CUI::SetListView(CListCtrl* lst)
{auto lStyle = GetWindowLongPtr(lst->m_hWnd, GWL_STYLE); // 获取窗口样式lStyle |= LVS_REPORT; // 设置为报表模式SetWindowLongPtr(lst->m_hWnd, GWL_STYLE, lStyle);// 给窗口设置样式auto dStyle = lst->GetExtendedStyle(); // 获取扩展样式dStyle |= LVS_EX_FULLROWSELECT; // 设置选择时选择一行dStyle |= LVS_EX_GRIDLINES; // 画网格线lst->SetExtendedStyle(dStyle); // 设置扩展样式
}void CUI::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_TAB1, mTab);DDX_Control(pDX, IDC_LIST1, lstlog);DDX_Text(pDX, IDC_EDIT1, txtDetails);DDX_Text(pDX, IDC_EDIT3, txtChat);DDX_Text(pDX, IDC_EDIT2, txtChatName);DDX_Control(pDX, IDC_COMBO2, cmbChat);
}BOOL CUI::OnInitDialog()
{CDialogEx::OnInitDialog();SetListView(&lstlog);InstallPage(new CUIWnd_0(this), IDD_PAGE_0, L"角色", TRUE);InstallPage(new CUIWnd_1(this), IDD_PAGE_1, L"周围");InstallPage(new CWndSet(this), IDD_PAGE_2, L"设置");lstlog.InsertColumn(0, L"消息", 0, 70);lstlog.InsertColumn(1, L"内容", 0, 700);lstlog.InsertColumn(2, L"时间", 0, 200);//PageINJ.Init(wAppPath);//PageRAN.SetAppPath(wAppPath);for (CString & txt : ChatPdName){cmbChat.AddString(txt);}cmbChat.SetCurSel(0);return TRUE;
}bool CUI::InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _Name, BOOL IsShow)
{if (CurPage >= (sizeof(WNDS) / sizeof(CDialogEx*))) return false;Pages[CurPage] = wnd;Pages[CurPage]->Create(IDD_WND, this);//Pages[CurPage]->SetParent(this);Pages[CurPage]->ShowWindow(IsShow);CRect rect;mTab.GetClientRect(&rect);rect.top += 32;rect.left += 5;rect.bottom -= 4;rect.right -= 5;Pages[CurPage]->MoveWindow(&rect);mTab.InsertItem(CurPage, _Name);CurPage++;return true;
}BEGIN_MESSAGE_MAP(CUI, CDialogEx)ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CUI::OnTcnSelchangeTab1)ON_WM_TIMER()ON_BN_CLICKED(IDC_BUTTON1, &CUI::OnBnClickedButton1)
END_MESSAGE_MAP()// CUI 消息处理程序void CUI::OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{// TODO: 在此添加控件通知处理程序代码*pResult = 0;int n = mTab.GetCurSel();for (int i = 0; i < CurPage; i++){Pages[i]->ShowWindow(i == n);}
}PTextManger CUI::getTxtManger()
{if (!txtManger)txtManger = new TextManger("F:\\语言包.txt");return txtManger;
}void CUI::loginok(ROLE_DATA* _roles, int count)
{PushLog(LOGTYPE::SYS, L"账号登录成功");NetClient::loginok(_roles, count);wnds.wndRole->lstRole.DeleteAllItems();CString txtInfos;for (int i = 0; i < count; i++){txtInfos = _roles[i].infos.value();txtInfos = txtInfos + L";";CString txtIndex, txtSex, txtMap, txtJob, txtCamp, txtRace, txtLv;CStringA stxtMap, stxtJob, stxtCamp, stxtRace;txtSex = ReadValue(txtInfos, L"1,", L";");txtMap = ReadValue(txtInfos, L"56,", L";");txtJob = L"job_" + ReadValue(txtInfos, L"37,", L";");txtCamp = L"camp_" + ReadValue(txtInfos, L"35,", L";");txtRace = L"race_" + ReadValue(txtInfos, L"36,", L";");txtLv = ReadValue(txtInfos, L"38,", L";");txtIndex.Format(L"%d", _roles[i].index.value());stxtMap = txtMap;stxtJob = txtJob;stxtCamp = txtCamp;stxtRace = txtRace;txtSex = SexName[txtSex == L"1"];wnds.wndRole->lstRole.InsertItem(0, txtIndex);wnds.wndRole->lstRole.SetItemText(0, 1, _roles[i].name);wnds.wndRole->lstRole.SetItemText(0, 2, txtLv);wnds.wndRole->lstRole.SetItemText(0, 3, txtSex);wnds.wndRole->lstRole.SetItemText(0, 4, getTxtManger()->ReadTextById(stxtCamp.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 5, getTxtManger()->ReadTextById(stxtMap.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 6, getTxtManger()->ReadTextById(stxtRace.GetBuffer()));wnds.wndRole->lstRole.SetItemText(0, 7, getTxtManger()->ReadTextById(stxtJob.GetBuffer()));}
}bool CUI::Tips(int code)
{CString logName;logName.Format(L"服务器提示:%d", code);PushLog(LOGTYPE::TIPS, logName.GetBuffer());// NetClient::Tips(code);return true;
}bool CUI::OnInited()
{SetTimer(0x10001, 50, NULL);return true;
}bool CUI::OnSvrChat(PCHAT_PRV _coder)
{CString txt;CString txtPd;CString txtName = _coder->name;CString txtInfo = _coder->txt;txt.Format(L"%d", _coder->ChartId.value());AfxMessageBox(txt);switch (_coder->ChartId){case 1:// 附近频道txtPd = L"附近";break;case 2:// 区域频道txtPd = L"区域";break;case 3:// 私聊txtPd = L"接收的私聊";// return OnChatPrivate((PCHAT_PRV)_coder);break;case 6:// 公会频道txtPd = L"公会";break;case 9:// 阵营频道txtPd = L"阵营";break;case 21:// 喊话频道txtPd = L"喊话";// return OnChatPublic((PCHAT_PUB)_coder);break;case 103:// 喊话频道txtPd = L"发送的私信";// return OnChatPublic((PCHAT_PUB)_coder);break;}txt.Format(L"[%s][%s][%s]", txtPd, txtInfo, txtName);PushLog(LOGTYPE::CHAT, txt.GetBuffer());return true;
}CString CUI::ReadValue(CString& txt, wchar_t* key, wchar_t* endStr)
{CString result = L"";int iStart = txt.Find(key);if (iStart > -1) {iStart = iStart + wcslen(key);int iend = txt.Find(endStr, iStart);if (iend > -1)result = txt.Mid(iStart, iend - iStart);}return result;
}void CUI::PushLog(LOGTYPE type, wchar_t* txt)
{struct tm newtiem {};time_t t;time(&t);localtime_s(&newtiem, &t); // 获取时间CString logName;logName.Format(L"%.4d-%.2d-%.2d %.2d:%.2d:%.2d", newtiem.tm_year + 1900, newtiem.tm_mon + 1, newtiem.tm_mday, newtiem.tm_hour, newtiem.tm_min, newtiem.tm_sec);lstlog.InsertItem(0, MsgName[(int)type]);lstlog.SetItemText(0, 1, txt);lstlog.SetItemText(0, 2, logName);
}void CUI::OnTimer(UINT_PTR nIDEvent)
{wnds.wndAIM->UI();CStringA tmp;tmp.Format("%d", Player.CurArea);txtDetails.Format(L"lv.%d.%s 生命值[%d/%d] 经验值[%d/%d] 当前所在场景[%s](%.2f|%.2f|%.2f)", Player.Level, Player.Name,  Player.HP, Player.MaxHP + Player.MaxHPAdd, Player.PlayerExp, Player.PlayerUpgradeExp, getTxtManger()->ReadTextById(tmp.GetBuffer()), Player.x, Player.h, Player.y);SetDlgItemText(IDC_EDIT1, txtDetails.GetBuffer());// UpdateData(FALSE);__super::OnTimer(nIDEvent);
}void CUI::OnBnClickedButton1()
{int nsel = cmbChat.GetCurSel();UpdateData(TRUE);if (nsel > -1) {if (ChatPdId[nsel] != -1) {Talk(txtChat.GetBuffer(), ChatPdId[nsel]);}else {TalkTo(txtChatName.GetBuffer(), txtChat.GetBuffer());}txtChat = L"";}SetDlgItemText(IDC_EDIT3, txtChat.GetBuffer());}

CUI.h文件的修改:引入 CWndSet.h文件,修改了 WNDS结构体

#pragma once
#include "afxdialogex.h"
#include "NetClient.h"
#include "TextManger.h"
//增加页面头文件
#include "CUIWnd_0.h"
#include "CUIWnd_1.h"
#include "CWndSet.h"
//游戏辅助UI类
// CUI 对话框enum class LOGTYPE {TIPS = 0,SYS = 1,CHAT = 2,MAX
};typedef struct WNDS {CUIWnd_0* wndRole;CUIWnd_1* wndAIM;CWndSet* wndSet;
};// #define MAX_PAGE_MAIN 3// 这里用了多重继承,这回有一个问题,函数名一样的会发生冲突
// 所以在继承的时候要注意函数名
class CUI : public CDialogEx,public NetClient
{DECLARE_DYNAMIC(CUI)public:CUI(CWnd* pParent = nullptr);   // 标准构造函数virtual ~CUI();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_MAIN };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持DECLARE_MESSAGE_MAP()union {CDialogEx* Pages[sizeof(WNDS)/sizeof(CDialogEx*)];WNDS wnds;};short      CurPage = 0;
public:CTabCtrl mTab;virtual BOOL OnInitDialog();bool    InstallPage(CDialogEx* wnd, int IDD_WND, CString&& _Name, BOOL IsShow=FALSE);afx_msg void OnTcnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult);
public:void SetListView(CListCtrl* lst);PTextManger getTxtManger();CListCtrl lstlog;
protected:CString MsgName[(unsigned int)LOGTYPE::MAX]{L"错误",L"系统",L"聊天"};CString SexName[2]{L"男",L"女"};CString ChatPdName[6]{L"附近",L"区域",L"公会",L"阵营",L"喊话",L"私信"};int ChatPdId[6]{1, 2, 6, 9, 21, -1};void PushLog(LOGTYPE type, wchar_t* txt);
protected:void virtual loginok(ROLE_DATA* _roles, int count);bool virtual Tips(int code);bool virtual OnInited();bool virtual OnSvrChat(PCHAT_PRV _coder);// 解析角色的信息,性别、种族、阵营等CString ReadValue(CString&txt, wchar_t* key, wchar_t* endStr);
public:CString txtDetails;afx_msg void OnTimer(UINT_PTR nIDEvent);CString txtChat;CString txtChatName;afx_msg void OnBnClickedButton1();CComboBox cmbChat;
};

AIM.cpp文件的修改:新加 SetRoleHide函数

#include "pch.h"
#include "AIM.h"
#include "extern_all.h"// 复制游戏数据包到自己的内存中
// Create是预留的一个接口暂时没用到
void AIM::SetHeadDatas(void* buffStart, bool Create)
{Isfree = false;unsigned lStart = (unsigned)&lId;unsigned lEnd = (unsigned)&endclass;memcpy(&lId, buffStart, lEnd - lStart);
}bool AIM::SetHeadCord(void* buffStart)
{Isfree = false;unsigned lStart = (unsigned)&lId;unsigned lEnd = (unsigned)&tx;memcpy(&lId, buffStart, lEnd - lStart);return true;
}// 怪物只有ConfigId没有名字,所以重写SetConfigID让它根据ConfigId获取中文名
void AIM::SetConfigID(char*& buffStart)
{GAMEOBJECT::SetConfigID(buffStart);Name = txtManger->ReadTextById(ConfigID);
}void AIM::SetRoleHide(char*& buffStart)
{// 下方的判断是用来判断当前属性的更新是否是我们玩家自己// this->lId == Client->Player.lId;int* ntRead = (int*)buffStart;int value = ntRead[0];ntRead[0] = 0;GAMEOBJECT::SetRoleHide(buffStart);RoleHide = value;
}

AIM.h文件的修改:新加 SetRoleHide函数

#pragma once
#include "GameOBJECT.h"
typedef class AIM:public GAMEOBJECT {
public:long long lId;float x;float h;float y;float face;float tx;float th;float ty;float tface;int IState;int endclass;// Create是预留的一个接口暂时没用到void virtual SetHeadDatas(void* buffStart, bool Create = true);bool virtual SetHeadCord(void* buffStart);// 怪物只有ConfigId没有名字,所以重写SetConfigID让它根据ConfigId获取中文名void virtual SetConfigID(char*& buffStart);void virtual SetRoleHide(char*& buffStart);
}*PAIM;


相关文章:

  • imx6ull - 制作烧录SD卡
  • 特征工程技巧—Bert
  • ResizeObserver监听画布尺寸改变动态渲染echarts
  • Lua 基础 04 模块
  • Linux 系统安全及应用
  • FFmpeg解复用器(解封装)简单测试【2】
  • 每日一练——分糖果2
  • 【Go语言精进之路】构建高效Go程序:零值可用、使用复合字面值作为初值构造器
  • CAPL如何发送一条UDP报文
  • 独立游戏开发的 6 个步骤
  • 游戏找不到d3dcompiler43.dll怎么办,分享5种有效的解决方法
  • 【全开源】种草分享|动态朋友圈|瀑布流|uniapp
  • MySQL—约束—外键约束(基础)
  • Scala 柯里化、sortBy方法
  • Linux配置java,maven,marshalsec环境
  • [笔记] php常见简单功能及函数
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • egg(89)--egg之redis的发布和订阅
  • FineReport中如何实现自动滚屏效果
  • HTML5新特性总结
  • Redis在Web项目中的应用与实践
  • vue的全局变量和全局拦截请求器
  • zookeeper系列(七)实战分布式命名服务
  • ​渐进式Web应用PWA的未来
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • # linux从入门到精通(三)
  • ###项目技术发展史
  • #Lua:Lua调用C++生成的DLL库
  • #QT(智能家居界面-界面切换)
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (八)Spring源码解析:Spring MVC
  • (二)c52学习之旅-简单了解单片机
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (几何:六边形面积)编写程序,提示用户输入六边形的边长,然后显示它的面积。
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)Thymeleaf用法——Thymeleaf简介
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .NET MVC 验证码
  • .NET 表达式计算:Expression Evaluator
  • .NET 将多个程序集合并成单一程序集的 4+3 种方法
  • .net 中viewstate的原理和使用
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .net打印*三角形
  • .Net面试题4
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149