内容参考于:易道云信息技术研究院VIP课
上一个内容:项目搭建
首先下图红框里是游戏启动的程序
游戏启动之后的名字(fxgame.exe)
一般游戏启动的架构:
第一种:登录器程序启动游戏主程序,然后游戏中完成登录。
说明:
也就是游戏会分为两个结构一个是登录器,另一个是游戏主程序,游戏的主要功能也肯定是在游戏主程序中,但是直接执行游戏主程序执行不了,必须要用登录器启动,原因有很多种情况,第一网络游戏的版本会经常更新,所以登录器启动的时候就可以验证一下版本,版本不行就更新,自己更新自己肯定不行,热更新中间也是有东西做跳板来做的,如果直接更新这个程序,也就是自己更新自己是一个很难操作的东西,第二主程序可能会被别人破坏,比如做硬件补丁,这时再用登录器检验文件发现CRC32和我登录器记录的不一样,这样就拒绝启动,这也是登录器的一个作用,起到一个防破解的作用,还有游戏主程序会有它自己的一套验证,也就是我们双击游戏主程序它其实是启动了,但是由于某种原因又退出了,所以要逆向分析这个原因是什么,然后还要分析登录器是怎样启动的游戏主程序,把这些东西都分析好,我们也就能做一个登录器了
第二种:登录器完成登录,传送token(输入账号密码点击登录会发送网络请求到服务器,如果密码账号都正确服务器会返回一堆乱码,也就是加密的数据,这个加密的数据就是token)至游戏客户端,游戏根据token登录。
说明:
然后这种在分析登录器的时候就不能只分析打开游戏客户端了,还要分析登录器的登录,这种方式启动的流程,首先是在启动器里登录,获取token,然后把token发送给游戏,游戏启动之后拿着这个token去访问服务器,看看这个token存不存,正不正确,如果正确就正常登录,如果不正确就退出
第三种:游戏客户端直接启动。
说明:
这种的启动之后会弹出一个窗口,用来输入账号密码登录,跟登录器一样,然后登录之后就关闭登录页面打开游戏页面,这种的就是一个ui显示隐藏的操作
上面的三种启动方式,都免不了从登录器到游戏主程序它们之间的通信,也就是跨进程的通信
进程之间传递信息的方式:就几种方法,如果遇到了只需要去了解对应的Windows api就可以了
1.命令行,用的最多
2.油槽管道,需要通过相关的api做入口点找我们需要的数据
3.共享内存,它很隐蔽,特别难做,需要从内存中读写去做这个事情
4.消息队列,这种特别少
5.信号量互斥量,只能传递简单的信息,复杂信息不好处理,之前一个篇章里的游戏就是用的信号量与互斥量
分析的时候就安装上面的五个一个一个的去排查,必定是其中的一个
如果任务管理器没有命令行这一列,鼠标右击 选择列,现在的系统是Windows 11,其它Windows肯定也都有这样的操作,应该会文字不一样但意思一样
然后勾选上命令行,再点确定就可以了
然后这些表头是可以,左右拖动排序的,这句话的意思懂得都懂
然后回到游戏,通过任务管理器看出它的命令行参数有很多,这就是一个典型通过命令行传递的操作
直接启动游戏客户端会弹出下图的弹框,然后就没反应了
然后接下来尝试把它的命令行全部复制下来,然后尝试直接启动游戏客户端
赋值命令行,首先打开x96dbg,附加到游戏,然后选择下图 改变命令行
然后赋值命令行
然后把游戏客户端发送到桌面快捷方式
然后把从x96dbg赋值的命令行,粘贴到快捷方式的目标里,然后双击
然后通过双击游戏客户端的方式就能正常启动了
然后在复制命令行的时候,游戏已经运行一会了,这时复制的命令行并没有成功,重新用登录器启动之后,再复制命令行,可以直接通过游戏客户端启动了,现在分析都有什么东西发声了变化,第一时间发声了变化,第二游戏它有一个隐藏的通信,过一段时间通信就会关掉,关掉之后就不能打开游戏客户端了
然后现在分析为什么不让打开了,首先它会弹框
这个弹框是在游戏进程中,不是登录器弹出的窗口
这个弹框是用MessageBox实现,MessageBox有一个特定就是不按确定它不返回,点了确定之后游戏会退出,这时就直接在MessageBox函数里下断点调试它,MessageBox已经启动了,函数头下断点无法触发,所以只能在ret位置下断点,然后 MessageBox有两个一个是 MessageBoxA一个是MessageBoxW,下图是在 MessageBoxA下断点
MessageBoxW下断点
然后点确定,就在MessageBoxA函数里断下来了
然后按f8,来当调用MessageBoxA函数的位置,这个位置没什么东西,应该是被封装了,比如封装成只需要传一个字符串,这个字符串就是弹框里的内容
所以按f8,再来当上一层
然后点击分析模块,就可以看到坐标有一个红线,顺着这根红线就可以找到从哪来的
然后顺着红线往上滑,就来到了下图红框位置
然后看到下图红框位置的函数,GetTickCount
GetTickCount函数是用来获取系统启动时间的,单位毫秒,上面说时间长了同样的命令行就打不开了,有两种情况一种是时间,一种是隐藏的通信,这里看到 GetTickCount函数 就可以确定它是通过时间做判断的
然后在下图红框位置,根据启动启动时间得出了一个差值,然后又cmp eax, 0x1D4C0,这个1D4C0是120000,然后eax是 GetTickCount 函数的返回值,也就是一个毫秒数,所以120000也是毫秒数据,然后120000 / 1000 = 120秒,然后这就破案了,为什么时间长了同样的命令行参数不能启动了,这因为命令行里肯定有一个东西代表了,一个毫秒数,这个毫秒数大于2分钟了,所以不能启动了
然后分析一下命令,看看哪一个数据可以代表时间
能代表时间的只有 7265218 了
然后eax = eax - esi,esi就可能是登录器传递的时间戳了,然后eax是第二个时间戳,它俩相减就得到一个时间的差值,差值超过2分钟就退出
然后在下图红框位置的函数得到的esi,一个call后面的eax,这个eax就要看做成函数的返回值
然后再往上滑还有 GetCommandLineA函数
GetCommandLineA函数说明,获取命令行
然后还看到了命令行传递过来的东西,如下图,直接就是明文数据,这就是一个给游戏公司提意见的点,如果把这些数据提前解析,解析出来之后进行加密,加密完,放到另一个变量里,使用时使用加密的数据,随着使用随着解密,这样只要找不到加密函数就破解不了,然后多调几个参数是命令行的无用函数做伪装,这个东西破解起来难度就更大了