当前位置:   article > 正文

使用Hook拦截socket函数解决虚拟局域网部分游戏联机找不到房间的问题——以文明6为例_文明6局域网刷不出房间

文明6局域网刷不出房间

前言

许多单机游戏都有局域网联机功能,尽管有些也提供了互联网联机功能,但是一般这些游戏的土豆服务器让玩家非常恼火,于是诸如游侠等对战平台则是其中一种选择。使用这些平台提供的局域网联机功能就可以获得比较稳定的联机体验。还有一种方法就是搭建虚拟局域网(VLAN)了,比如使用N2N就可以搭建一个(需要自备服务器),或者用ZeroTier、Radmin LAN这类工具。

但是许多人在搭建好一个自己的局域网之后,却发现进了游戏怎么也找不到房间。

局域网联机的游戏基本上是通过向 255.255.255.255 发送 UDP 广播数据包来传播游戏房间信息,但是 Windows 只会在首选的网络接口(网卡)上发送全局 IP 广播数据包,也就是说局域网游戏的信息没有被 Windows 在虚拟局域网接口上广播

以上摘自https://bugxia.com/3128.html,原出处https://www.bilibili.com/read/cv14633088

本文以文明6这款游戏的找房机制为例,采用Hook技术,拦截游戏对UDP广播的发送、接收等操作,并用一系列的方法使得游戏的广播能够成功发送到所有网卡,并成功接收到来自其他客户端的回复。

本文会详细说明如何分析文明6的局域网联机找房机制,以及Hook相关函数的细节,所以内容可能比较冗长,希望你能耐心看完。

在开始之前,希望你能对文本涉及到的Windows编程、socket编程、Hook技术、网络抓包、反汇编调试等内容有所了解,这样可以便于理解。否则对于初学者来说可能会有一定的难度。

还有一点,本文所提出的方法,可能并不适用除文明6以外的其他游戏,因为每个游戏的具体机制有所不同,需要通过分析得出。如果你熟悉分析方法,可以很容易地对不同的游戏找到适用的解决方案。而且,本文的方法仅适用与真实的或者虚拟的局域网,而不适用于游侠这类同样使用Hook的对战平台。

如果有IPv6地址,可以考虑使用该项目提供的工具:xaxys/injciv6: 文明6联机 - 基于IP的游戏发现 (IPv4/IPv6) (github.com),相关视频:https://www.bilibili.com/video/BV1qV411X7FP,其在本文基础上添加了IPv6直连的功能,可以不需要组网。不过这里提醒一下,IPv6的入站比较复杂,目前绝大多数的光猫和路由器都是默认开启了防火墙的,需要依次到光猫和路由器关闭IPv6的防火墙(大部分都可以关),同时在系统放行游戏的网络包,为了安全,不建议关闭系统的防火墙。至于移动数据的IPv6上网,不确定能不能成功入站。

正文

本文代码及编译好的二进制文件可以在这个仓库找到。

https://gitcode.net/PeaZomboss/miscellaneous

源代码在文件夹230130-hookgamesendto
若要下载二进制,请到https://gitcode.net/PeaZomboss/miscellaneous/-/releases/civ6-hook-binary

未来有关的代码均可在上面的仓库找到。

起因

去年的时候我和哥们一起玩起了文明6,为了能够一起联机游玩,就找了许多方法,后来找到了由Bug侠基于N2N开发的EasyN2N(在这里感谢作者免费提供服务器供我们使用)。但是经常遇到找不到对方房间的问题,后来逐渐排查出了原因,就是UDP广播没有发出去的问题,也发现EasyN2N有一定的解决办法。

比如其集成了WinIPBroadcast这款广播转发工具,不过在实际使用中发现有的时候没有作用。但是手动把虚拟网卡的跃点改小,提高其优先级是一个有效的方案。但不知是哪边的bug,这个跃点会时不时的自动变回去,很是恼火,就想找一个方便的方法。

由于N2N这类技术是使用虚拟网卡来实现虚拟局域网的搭建,所以我们只要想办法把游戏的广播发到虚拟网卡就可以解决问题了。不过实际上把广播转发到每张网卡就可以了,因为这样比较方便实现。

于是我就想到了使用Hook技术,把游戏发的广播内容拦截了,再给他转发岂不是就能解决问题了?

于是就上网查了一下资料,花了不少时间上手做了一个demo,自己用着感觉不错(其实有bug,能不能成功还是看玄学),然后几个月没怎么玩了,后来看到文明6正在更新领袖包,打算等更新完了再快乐联机,又想到之前写过的代码,就想着把原来的代码梳理一下,然后重新写个新的,顺便温习一下相关知识。

好了事情的起因就是这样子了。

经过

正当我以为一切顺利的时候,我发现事情没有那么简单,实际上不是简单Hook并转发一下广播就能实现的。这不仅涉及到sendto函数的基本用法,还有一些比较复杂的细节,包括端口复用如何收发包的问题。于是又要涉及到对于收包函数recvfrom,以及select函数的拦截与使用。

后来我根据抓包的结果,推测文明6游戏的逻辑,仿制了一个类似的测试工具,并在此基础上不断调试。后来为了确保能实现一个比较准确的结果,拿出了x64dbg这一神器对游戏进程进行了一些调试,最终得出了游戏找房过程的具体方法,并复刻了一个在原理上几乎是完全一致的工具。

有兴趣可以阅读其源码。关于游戏的调试过程,我会在后文进行一个介绍。

总之,在一段时间的努力之后,我终于从sendto到recvfrom和select三位一体进行精准Hook,拿下了最终的成功。

技术介绍

本文的代码实现部分使用Hook技术(确切说是Inline Hook)以及socket技术,由于还要涉及对其他进程的Hook,所以还要用到注入技术。

本文的分析过程涉及到网络抓包及软件调试技术,这个会在游戏分析部分进行具体说明。

Hook介绍

Hook技术一般翻译为钩子技术,就是提前在特定事件或消息处挂上钩子,等执行到此处就会触发钩子,执行钩子的代码。Windows系统提供了SetWindowsHookEx等一系列函数实现Hook的功能,不过这和我们实际用到的不太一样。

本文所用的Inline Hook就是把任何函数调用的前几个字节改成一句跳转指令,跳转到自己的地方执行,然后返回到原来的主调函数,此时就获得了函数的参数等一系列信息。许多人做的微信Hook就是这么搞的,不过缺点就是一旦函数地址或者参数变了,就得重新编写相应的代码。

有关Inline Hook的具体介绍,请看本人写的这篇文章。本文所用的方法就是以此为基础的。

当然对于游戏来说,其发送广播必然离不开系统调用sendto或者WSASendTo,而接收包多是通过recvfrom,所以我们只要hook相应的系统调用就可以了,而大部分系统函数的地址都是完全公开的。

当然如果只是这样还只能hook自己的进程,想要hook其他进程就得先把hook代码编进一个dll,再想办法让目标进程加载这个dll,这个过程叫注入(inject)。

当我们的dll打入敌人内部,就可以窥探其全部的虚拟地址空间,这样我们就可以大施拳脚,为所欲为了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/160437
推荐阅读
相关标签