《决战》是一款非常古老的RPG游戏,作为热血传奇同期的热门游戏也深受7080后的喜爱。

在十几年前玩这个游戏时,我也使用过瞬移穿墙,快速施法秒怪等功能的辅助。

下面我们就用一个自己架设的单机版来回顾一下当年辅助开发的流程,并从安全角度来对这些功能进行防护分析。

一、找到明文发包函数

首先我们对功能的数据需求进行分析。

瞬移穿墙是法师专利,常规情况下法师的瞬移是不可以穿墙的,为了实现穿墙功能,我们一定要从发包入手,所以首要目标是找到明文发包函数。

然后是快速施法,既然有这个功能说明这个功能也很可能是通过快速的协议重发实现的,所以我们也要从明文发包函数入手。

xdbg32附加游戏,在send下断,走路游戏断下

重复下断,做吃药或者瞬移动作,观察堆栈发现堆栈返回是不同的,说明游戏没有线程发包

多次执行到返回,找到公共CALL和功能CALL临近的位置,为明文发包函数头部

以上都是新手的基础操作,没啥难点。

二、瞬移穿墙分析

在技能CALL上下断,进行瞬移,我们来观察下参数

明文函数有2个参数,第一个是0,第二个是结构体

结构体中+8又是一个结构体,作为明文封包结构体,而+C则是包长,其他的都写固定值即可

分析明文封包结构体

+0的6D表示技能包头,BYTE型

+1是2712,应该是角色ID,DWORD型

+5的07是瞬移技能ID,这个通过和其他技能的对比能够观察出来

然后+6和+A则是目的地的X和Y坐标,DWORD型

我们自己申请内存构建结构体,用代码注入器进行测试,发现这个封包是可以穿墙的,但是正常游戏是会撞墙的

这说明在上面有某些代码对这个坐标进行了校验和修正

我们向上分析,首先找到了组包函数

这个函数的参数就是XY坐标,并且是修正过的

那么我们去追这两个坐标的来源

修正的X和Y分别来源于ecx+8和ecx+C,而最终来源则是上面的call 0x004A2C20的返回

我们在看下call 0x004A2C20的参数

发现这个CALL的4个参数分别是当前的XY和目的地的XY,而在经过这个CALL之后,目的地的XY会被修正为不可穿墙的坐标

如果我们想手动游戏实现穿墙,可以HOOK下面的4EFA9D来将目的地的坐标传递给修正后的坐标

如果觉得HOOK代码比较麻烦的话,也可以用其他的办法,就是讲004EFA9D处的机器码改写为8B 49 90

因为我们在这个位置下断后发现,ecx-70里面存放的恰好是修正前目的地坐标的结构,而[ecx-70]+8和+C指向的就是目的地坐标

这样我们只需要写内存就可以。

这样处理以后,我们就可以瞬移穿墙了,这里并没有用到其他的数据,接下来我们分析快速施法。

三、快速施法的实现

我们回到技能CALL的位置,对一个怪物释放技能,并观察参数

封包结构体和瞬移很像,其中的包长变为了6

+0同样是包头0x6D

+1是怪物ID,DWORD型

+5是04,代表技能“冰魄”,BYTE型

我们用代码注入器对这个技能进行快速释放,发现技能的释放频率明显提升,以下是普通情况和直接发包的对比

在这个明文封包里面,我们的技能ID可以固定,其实需要传递的只是一个最近的怪物ID

所以我们接下来要对角色和周围对象的数据进行分析

四、角色对象分析

通常情况下角色对象我们要从角色的血量入手,但是当你去扫描角色血量时,会发现直接扫到一个非游戏模块的基地址

无论我们切换装备还是吃药,得到血量都是基地址,此时可能有些人认为自己已经找到了角色对象,就凑合用了。

其实这个数据并不是我们想要的答案,因为这个游戏的对象下血量只有在被近战攻击时才会被正确的写入,其他时候都是不变的或者有错误的。不止是角色,怪物也是如此。

所以我们想找角色对象,需要让怪物攻击掉血后进行扫描。

重新扫描可以得到一个非基地址的结果

对这个结果下访问断点,可以得到+58偏移

ce扫描rbx可以得到两个基地址,其中的一个基地址的结果可能会变化,所以我们选择另一个

对005780C4进行访问,可以得到1ACC偏移和基地址0x5765F8

血量公式[0x5765F8+1ACC]+58

角色对象搞定了,接下来分析周围遍历

五、周围对象遍历

周围对象遍历还是从血量入手,既然前面说到了远程攻击无法改变怪物对象下的血量,那我们就找个怪物去砍他

用CE扫描到怪物血量

用xdbg观察地址,发现怪物对象和角色对象的结构基本是一样的,也就是说第一层偏移也是+58

在血量上下访问断点

向上分析eax,得到来源[esp+10],继续分析得到来源于CALL的返回

在这个CALL里面我们可以得到一个二叉树的遍历,过程就不详细分析了,最终的公式如下

[[0x5765F8+1B0C]+4] 根节点 节点==[0x00590790]结束遍历

+0 左子树

+8 右子树

+C ID

+10 对象

对象+58 当前血量(没啥用的数据)

[对象+2C]+0 名字ASCII

对象+224 X

对象+228 Y

这些数据都是最基本的,没有什么难度,通过观察对比可以得到+158是死亡标志,怪物死亡后

六、周围对象分类

对象类型的重要性往往会被忽略,但是当你用到它时又会发现这个数据无从下手。

如果不对类型进行判断,我们就会对NPC,建筑物,甚至自己发送技能包,所以这个数据是不可或缺的。

最常见的入手点是通过和对象的交互进行分析。比如打开NPC,攻击怪物等等。

我们找到一个NPC,通过明文发包函数断到打开NPCCALL

再次返回一层

接下来找一个怪,用左键攻击他,得到普通攻击CALL

再次返回后发现和打开NPC的外层是一样的

这说明普通攻击和打开NPC是在同一个函数下的,我们需要找到区分这两个功能的跳转。

在头部下断,立刻断下,单步执行找到跳出到返回的跳转,然后绕过这个跳转,在下面下断做打开NPC动作

单步执行到一个dec代码下面时发现打开NPC不跳,攻击怪物跳

到CALL里分析eax的来源

这里跳转的ecx决定返回的eax值,所以我们只要分析ecx的来源即可,向上分析,经过一个inc后来源于+248偏移

这个偏移恰好在对象下,经过多个对象的观察,我们得出了以下结论

这里的建筑指的是传送门之类的,未知是一些看不到的对象

分类解决了,接下来就是怪物的死亡标志,这个数据是通过对对象的属性进行观察得到的,因为怪物死亡后0.5秒左右才会改变,所以如果用CE搜索的过快可能会把这个标志过滤掉

死亡标志的偏移是+158

七、封装数据,编写逻辑,实现功能

搞定了数据以后,我们就可以实现这个自动释放技能打怪的功能了,

首先我们需要通过二叉树读取到周围对象的信息

    void objTree(DWORD node)//遍历周围对象二叉树
{try{DWORD left = (DWORD)(node + 0);DWORD right = (DWORD)(node + 8);DWORD ObjID = (DWORD)(node + 0xC);DWORD dObj = (DWORD)(node + 0x10);objarr[i].setID(ObjID);objarr[i].setDeath(*(BYTE*)(dObj + 0x158));objarr[i].setType(*(DWORD*)(dObj + 0x248));objarr[i].setCoord(*(DWORD*)(dObj + 0x228), *(DWORD*)(dObj + 0x22C));char* name = (char*)(*(DWORD*)(dObj + 0x2C));objarr[i].setName(name);char* isdeath = "";if (objarr[i].getDeath())isdeath = "死亡";elseisdeath = "活着";DbgPrintf_Mine("%X ,%s ,%X ,%s ,%d ,%d ,%s", dObj, objarr[i].getName(), objarr[i].getID(), objarr[i].getType(), objarr[i].getCoord().X, objarr[i].getCoord().Y, isdeath);i++;if (left != *(DWORD*)Base_End){objTree(left);}if (right != *(DWORD*)Base_End){objTree(right);}}catch (...){DbgPrintf_Mine("二叉树读取异常" );}
}

然后我们要在这些对象中筛选出最近的、活着的、在技能射程范围内的怪物

Object getNearest()//取最近距离的,活着的怪物
{getObj();DWORD a = 1000;DWORD b = 1000;Object cNest = Object();for (int j = 0; j < i; j++){b = getdistance(objarr[j]);if ((a > b)  && (objarr[j].getDeath() == 0) && (objarr[j].getTypeid() == 0)){a = b;        cNest = objarr[j];}}return cNest;
}

在发送封包的代码中我们加入射程判断,并对射程在15以内的怪物释放技能

void sendPacket()    //发送封包
{Object obj = getNearest();if (getdistance(obj) < 15){static char buf[0x500] = { 0 };static char buf1[0x500] = { 0 };memset(buf, 0, 0x500);memset(buf1, 0, 0x500);packet1* pkt1 = (packet1*)buf;packet2* pkt2 = (packet2*)buf1;//组包过程pkt2->packHead = 0x6D;pkt2->id = obj.getID();if (pkt2->id == 0)return;pkt2->num = 2;pkt1->base = 0x517788;pkt1->a1 = 1;pkt1->pack2 = pkt2;pkt1->lenth = 6;pkt1->a2 = 1;pkt1->a3 = 0x400;pkt1->skillId = 0x6A5A;//内联汇编调用明文发包函数DWORD call1 = call_mingwen;DWORD b = (DWORD)&buf;__asm{pushadmov eax, bpush eaxpush 0mov eax, call1call eaxpopad}}
}

最后我们只要开一根线程去不断的调用技能函数即可

int ii = 0;
void myThread()
{    ii = 0;while(ii == 0){Sleep(100);sendPacket();}
}void endThread()
{ii = 1;
}

以上就是这个功能实现的全过程,非常的简单,除了数据分析的过程稍长一些,逻辑代码非常少

后面我们还可以加入一些远程传送,自动打怪的功能

八、游戏安全角度的对抗

以上的功能虽然很暴力,但是从游戏安全角度去做检测也是非常简单的

1、首先是穿墙瞬移的部分,我们可以通过CRC去进行校验,保证代码不被普通改写。

2、其次是快速施法,我们可以在封包中加入时间戳,或者在服务器对封包间隔做校验,这个处理起来其实是很容易的

3、如果后面用到了远程传送,我们也可以做传送距离的校验,一般来说,封包传送的最大距离是能够遍历到的最远距离,

而玩家能够实现的距离则是一个屏幕内能看到的距离。

其实所有的功能只要在服务器做好严格的校验,就很难出现类似的BUG,本地的检测在协议面前很难发挥作用。

复古决战快速施法穿墙秒怪分析流程及安全防护相关推荐

  1. Clumpify:能使 Fastq 压缩文件再缩小 30% 并加速后续分析流程

    由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中链接. Clumpify 是 BBMap 工具包中的一个组件,它与其他工具略有不同的是 Clumpif ...

  2. RNA-seq数据上游分析流程(从原始数据开始)

    数据分析的基本思路 (1)从ncbi的geo或者其它数据库中查找自己感兴趣的RNASeq数据,至少要求给出如下信息: (2)对芯片数据进行质量控制评价及处理(如果质量差的话,每个样本都应该处理), 可 ...

  3. 一种用于EEG超扫描研究的分析流程

    超扫描方法使研究人员可以在自然环境中测量两个或更多个体之间神经活动的动态相互排列.超扫描研究日益增多需要开发一种透明且经过验证的数据分析方法,以进一步推动该领域的进一步发展.我们开发并测试了双脑电图分 ...

  4. 【bioinfo】融合检测软件FusionMap分析流程和报告结果

    文章目录 写在前面 FusionMap融合检测原理 FusionMap与其他软比较 FusionMap分析流程 FusionMap结果文件说明 FusionMap mono CUP设置 图片来源: h ...

  5. 弘玑Cyclone成功入围《2022爱分析·流程挖掘厂商全景报告》,流程智能产品受到广泛关注

    8月25日,国内知名数字化市场研究咨询机构爱分析正式发布<2022爱分析 ·  流程挖掘厂商全景报告>(以下简称"报告").弘玑Cyclone作为超自动化领导者,其自主 ...

  6. QCon大会实录:PB级数据秒级分析-腾讯云原生湖仓DLC架构揭秘

    导语 ‍‍‍‍文章整理了全球软件开发大会QCon<PB级数据秒级分析-腾讯云原生湖仓DLC架构揭秘>.大数据基于海量数据的分析,硬件.存储.计算资源尽量都可以用廉价的资源完成,如何在廉价资 ...

  7. 生信分析流程构建的几大流派

    导言 构建生信分析流程是生物信息学从业人员必备的技能之一,对该项能力的评估常常是各大公司招录人员的参考项目之一. 在进行 ngsjs 项目时,我做了一张示意图来表示一些高通量测序数据分析项目重现性的要 ...

  8. Nature子刊:宏基因组中挖掘原核基因组的分析流程

    宏基因组中挖掘原核基因组的分析流程 从宿主相关的短读长鸟枪宏基因组测序数据中恢复原核基因组 Recovering prokaryotic genomes from host-associated, s ...

  9. MPB:亚热带生态所谭支良组-基于微生物成分数据的差异zOTU分析流程

    为进一步提高<微生物组实验手册>稿件质量,本项目新增大众评审环节.文章在通过同行评审后,采用公众号推送方式分享全文,任何人均可在线提交修改意见.公众号格式显示略有问题,建议电脑端点击文末阅 ...

最新文章

  1. The number of Oracle redo threads (2) is not the same as the number of checkpoint threads (1)
  2. Hive+LDAP+Sentry
  3. python Multiprocessing Pool 应用
  4. 截取一段字符串中,两个指定字符串中间的字符串
  5. PHP include语句和require语句
  6. JavaEE 企业级分布式高级架构师(七)MongoDB学习笔记(3)
  7. java 后端处理PDF图册
  8. 牛客网 - 编程初学者入门训练 - 分支控制(BC50~BC77)
  9. css 自制一些小特效
  10. cim系统(cim系统包含哪些部分)
  11. 计算机教学中扩词扩句的应用,【教学设计】学习扩写 ——部编人教版九下第一单元写作...
  12. miui7开发版 Android6.0,Android 6.0 MIUI7开发版内测开始推送:
  13. android 8 平板,击败Android平板:Windows 8志在必得
  14. ARC下循环引用的问题
  15. ROS下安装和运行SVO数据包和实时测验的过程记录
  16. java中计算三角形的角度
  17. linux 桌面 修复工具下载,恢复ubuntu20.04默认桌面管理器
  18. POJ - 1789 Truck History (最小生成树)
  19. qt样式表设置边框_QT样式表
  20. 什么是SaaS,SaaS有哪些优缺点?

热门文章

  1. 计算机烧毁,终极:计算机主板烧毁了吗?为什么会燃烧?
  2. iOS OC利用imageview属性切出类似圆柱图形
  3. NET新手遭遇问题(九)
  4. FL studio 20简易入门教程 -- 第四篇 -- 钢琴卷帘窗口与单轨乐器编辑界面
  5. ping不通 telnet通
  6. DC-DC15-150V降压5V0.8A 替代PN6005、PN6006电源驱IC
  7. 【编程实践】为了带你搞懂RPC,我们手写了一个RPC框架
  8. 查询人数最多的部门名字
  9. 使用前端js代码开发了一个图片转ico图标的功能
  10. actor 模型原理 (二)