游戏网络架构逆向分析--1
Posted #A#
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了游戏网络架构逆向分析--1相关的知识,希望对你有一定的参考价值。
测试需求和拆解
网络游戏客户端与服务端协同形式:
一般分为两种情况:
- UI操作->吃药-> 生命值增加-> 发送服务器 (发送结果型)
- UI操作->吃药->发送请求吃药->服务器验证->服务器完成吃药->客户端同步显示
发送结果型:
首先在界面里按了吃药的操作,按下吃药的操作以后,生命值增加,客户端会看有没有药水,有没有cd 能不能吃,生命值就增加了,然后把这个血量发送给服务器,但发送给服务器前的这个是可以改的比如直接改成999999,这不就无敌了吗,所以用这种操作往往会有一系列加密的技术防止去修改,但再怎么修改本质上就是能改,这不是技术高低决定的,是这种结构就决定了能改,大部分都不会采用这种结构
另外一种比较完善的:
UI操作,首先检测有没有药水,在不在cd,能不能吃,然后告诉服务器要吃药了,服务器收到这个要吃药的请求也要看服务器上的数据:有没有药水,在不在cd,能不能吃,然后服务器就把吃药操作完了,接下来服务器把血量写到数据库里,再给客户端发送个消息 吃药完成了,这个过程是不是就严谨了很多,从整个流程看,可攻击的地方很小,在客户端和服务端都检测了一次,客户端的检测排除掉了以后,服务端的压力就会变小,这个主要是为了保护服务器,有的游戏就会把第二步取消掉了,都由服务器完成,这样服务器的压力就会大,服务器就有可能变卡
实际上,不是所有游戏都采用第二种,其实大部分的游戏都是第一种和第二种相结合(安全本质就是经济的对决),用第二种方式行,但成本比较高,这是一个吃药的操作,但有的操作非常频繁,比如走路,这种操作在服务器上验证是比较困难的,在服务器验证困难就会消耗大量的时间,客户端是一个面对服务器,服务器是一个面对N个玩家,所以同一时间要处理大量的消息,虽然现在硬件水平变好了,但依然还是很有压力的,有的时候服务器不得不放弃一些验证的操作,改用第一种结果式的发给服务器,从而就造成了漏洞,有的时候用了第二种,但是连续性的,比如需要三个第二种操作才能完成整个操作,如果其中某一个被我们人为忽略掉了,修改掉了,也会造成漏洞,只要都是在网络通信这块
网路通信是一个网络游戏的核心命脉,可以说大多数的游戏漏洞都是利用网络通信设计的不合理来实现的,比如绝地求生游戏中早期出现的一击必杀,瞬移等漏洞
逆向分析游戏宏发送数据和接收数据的过程,寻找游戏数据包明文发送与接受的关键函数,并且尝试利用该函数发送和接收数据
对于网络游戏中数据包漏洞利用的特点,给出检测和修复建议
网络游戏通信操作模型
UI操作 -》组织数据-》加密数据-》发送数据
接收数据-》解密数据-》分发数据-》使用数据
比较小型的会用单线程通信
一般大多是多线程通信
- 线程A:UI操作-》组织数据-》加密数据-》写入数据至发送区
线程B:读取发送区数据-》发送数据 - 线程A:接收数据-》解密数据-》写入数据至分发区
线程B:读取分发区数据-》分发数据-》使用数据
常见函数:
send recv 一般用于tcp通信,默认为阻塞型(可以改成非阻塞)
sendto recvfrom 一般用于udp
WSASend WSARecv 一般配合完成端口使用
通过逆向分析确定游戏明文数据包发送数据过程
数据包有关的关键信息:
char* buffer 数据包
unsigned len 数据包长度
我们要找的是明文数据发送的那个函数,要实现这个过程,至少要提供明文的数据包和数据长度
这个数据包跳过去一定有可辨识的,比如说话123,那里面就是123,里面就有,这就是明文,使用技能就有技能的ID或者编号,使用物品就有物品的代码,光有数据包不行,本身来说就是一段数据,就是一个指针,那数据包到底多长必须得给出来,长度不可能太长,总不可能发个这么长的片把?长度一般就是几百几十的样子,也可能数据包和包长混在一起的,数据包前面就是包长,后面就是内容,这样就只能看到一个东西,不管是哪一种,这个都是很敏感的东西。发送数据是这样的,那么接收数据也是一样的道理,也是这两个关键的信息,不然不好解析。
首先connect和WSAConnect下断
登录
可以直接看到IP地址
翻一下栈 ,这就是ip和 端口
随便看看调用过程
返回值等于-1就执行WSAGetLastError
这个地方大概就是它建立连接的地方,没什么太多可以注意的
但有一个地方还是要注意,如果连接成功,能拿到它的套接字,这个套接字肯定会保存起来
这个connect往上跳
发现是个虚函数
传入的两个参数是IP地址和端口
这个地方应该就是连接,连接完了要发送账号密码的操作
这个ecx也先保存一下
然后send和WSASend都断下
发现send被调用
上面这四个传递参数就比较奇怪 他可能是编译器的问题esi代替了 ecx,第二种可能是编译器的优化策略,但这种优化策略很少见
这个地方直接暴露了这发送失败了 ,相当于给别人提供武器了
这个函数没啥,也就是个发送的封装,也没什么值得一提的东西,还得看看上级
就比较明显了,这是数据的发送过程
这参数一看就是数据包和数据包长度
这就要测试是不是,看看数据包内容,内容看不懂,因为不知道是啥样的数据包
那我们就自己发送一个可以分辨的数据包
直接是明文了,直接改一个
所以这个地方恰恰就是我们想要的
这个 地方又是个虚函数,和connect很像
ecx = 3CDAF4A8
发送数据的时候要建立网络连接,指针一定是和跟网络有关系的值
这是个虚函数 就是thiscall 用 ecx传递参数
改一下参数,eax ebx改成0看看崩不崩:
结果也只是断线了,但没崩溃什么的问题,所以这个函数用法就是得到ecx就可以,而ecx可以通过网络连接获取,所以只要在这个地方做个小小的HOOK就能知道这个函数是什么样的情况了,有哪些地方调用了它,发送的是什么内容看看这个函数:
这就是我们发送数据的过程
往下翻就看到了刚刚那个发送数据函数 esi这个东西应该就是加密好的数据放进来了
上面那个函数应该就是加密数据的函数
在发送数据这截取
发现这貌似是个明文.....
一开始:
调用完那个加密函数:
数据包本身数据是没有变化的 就只加了个EE 加EE主要是为了防止粘包,服务器好处理,但里面没有个长度有关联的数据 万一也出现了EE 就寄了,如果数据包里没有长度光靠结尾加个EE是解决不了问题的,而且,居然没有加密的过程?可能是因为这是比较早期的客户端,没有加这个,当然,对于我们逆向来讲,加不加密不重要。目前来看 这个是只加了个EE
我们使用发送数据肯定是使用那个过程的发,在这也可以用那个send的发,但其他游戏加密肯定很复杂,那肯定是要调用本身的加密过程来完成加密的
问:
这段函数干了什么 ,EE咋加上去的,这个循环用C++还原出来
通过逆向分析确定游戏明文接收数据过程
基本上用的send,反过来就是recv
eax是长度 eax 309说明这里有过个数据包
这里又出现EE 而数据包里也有EE..不就解析么
这个esp+edi+37C edi现在是0 表明这个可以变化,这是个典型的数组
一般数组是 esp+edi*4+x
esp+37C 就是 char* buffer[0x800]
因为这前面传了个0x800内容,所以大小应该就是0x800,所以前面压栈压了个b78这么大
0x800-0x37C+4刚好是0x800 esp+37C是局部变量的buf的指针
edi后面肯定会处理让edi+
这地方操作就相当于 cl = buf[0]
if(buf[0]==0xEE)
然后一顿操作
edi++ 这肯定也是个循环 读取数据包,肯定就读取到EE结束
2个EE结尾了就不跳了
很明显是用的结构体传参
这个函数就是 ebx相当于指针,esi,edi相当于里面两个内容
这个应该是thiscall 但是用 eax来代替了ecx
传了esi edi 肯定就是数据包的内容了
直接肉眼可见了
刚好EE前
自己发消息接收试试
这个时候改一下:接受到的数据也变了
这地方就是接收数据
发现类都是一样的
首先在网络连接建立的时候会创建一个类,它的指针在我们网络连接的时候就能截取到了,截取到了以后,我们发送数据,接收数据都能够用。发送数据刚刚看了是标准的虚函数,但这个接收数据,因为代码优化的情况下,不是虚函数,用起来就比较麻烦。
首先
这个函数里就是用了eax来代替了ecx,这个函数要调用起来,不写汇编代码还比较麻烦。。但用起来肯定没啥太大问题,所以我们关键就是这个点。接下来要做的就是大量数据包分析了,接下来要把所有数据包打印出来,然后看是什么情况,这次核心目的就是尽量少去逆向,尽量用封包看看能不能把游戏构建起来,尽量尝试性的往脱机走走
Android 逆向逆向修改游戏应用 ( 分析应用结构 | 定位动态库位置 | 定位动态库中的修改点 | 修改动态库 | 重打包 )
一、应用结构分析
分析上一篇博客 【Android 逆向】逆向修改游戏应用 ( APK 解析工具 | 解包 -> 分析 -> 重打包 -> 签名 流程 ) 解包后的文件 ;
在 lib 目录下 , 有 armeabi-v7a 和 x86 两个 CPU 架构的动态库 ;
一般情况下 , 逆向都在模拟器中进行 , 模拟器中可以拿到 root 权限 , 并且权限管理没有真机那么严格 , 这里推荐删除 armeabi-v7a 架构的动态库 ;
此外 , 该应用检测出了 Unity3D 引擎 , 那么该应用的核心逻辑都在 Unity3D 中 , 如果要修改应用 , 需要修改 U3D 对应的动态库文件 ;
二、定位动态库位置
Unity3D 引擎对应的资源都在 apk\\unpack\\Game\\assets\\bin\\Data 目录下 ,
动态库资源都在 apk\\unpack\\Game\\assets\\bin\\Data\\Managed 目录中 , 如果要修改程序的逻辑 , 都在 C# 代码编译的 dll 动态库中 ; 本应用的相关逻辑是在 Assembly-CSharp.dll 中 ;
三、定位动态库中的修改点
使用 32 位的 IDA 打开上述 Assembly-CSharp.dll 文件 , 将下面红色矩形框中的 sub 减法运算 , 修改为 add 加法运算 ;
选中这个 sub 指令 ,
点击 Hex View-1 面板 , 发现 sub 对应的二进制数据是 59
;
将其修改为 add , 就需要知道 add 对应的二进制数据是多少 , IDA View-A 中选中 add , 然后查看 Hex View-1 中的二进制数据 :
add 操作对应二进制数据 58
;
这里修改时 , 将 0x354A6 字节的 59
修改为 58
;
四、修改动态库
使用二进制查看工具 , Ctrl + G 快捷键 , 跳转到 0x354A6 位置 , 发现值为 59
;
直接选中后 , 编辑该值即可 ;
五、重打包
将修改后的动态库放回原来的位置 ;
删除 sing 和 repack 目录 ;
继续执行程序 , 会在检查当前 " 解包 -> 分析 -> 重打包 -> 签名 " 流程 , 执行了哪些部分 , 发现 解包 , 分析 完成 , 重打包 和 签名没有完成 , 执行程序后 , 会自动进行后续 重打包 和 签名操作 ;
执行完毕后的 apk/sign/Game.apk 就是重打包后签名的文件 , 可以执行该 APK 文件 , 验证修改是否生效 ;
以上是关于游戏网络架构逆向分析--1的主要内容,如果未能解决你的问题,请参考以下文章
Windows 逆向使用 CE 分析内存地址 ( 运行游戏 | 使用 CE 工具分析游戏内子弹数量对应的内存地址 | 内存地址初步查找 | 使用二分法定位最终的内存地址 )
Android 逆向逆向修改游戏应用 ( 分析应用结构 | 定位动态库位置 | 定位动态库中的修改点 | 修改动态库 | 重打包 )
Windows 逆向OD 调试器工具 ( CE 工具通过查找访问的方式找到子弹数据基地址 | 使用 OD 工具附加游戏进程 | 在 OD 工具中查看子弹数据地址 | 推荐 )
Windows 逆向OD 调试器工具 ( CE 中获取子弹动态地址前置操作 | OD 中调试指定地址的数据 )
好课分享:易道云 C语言C++零基础到大神全栈课程(逆向游戏开发架构反外挂) 百度云
Windows 逆向OD 调试器工具 ( OD 附加进程 | OD 调试器面板简介 | 反汇编窗口 | 寄存器窗口 | 数据窗口 | 堆栈窗口 )