典型的数据包解析函数¶
要接收和处理数据包,游戏客户端在绘制帧前会做类似清单 10-2 的事情。
void parseNextPacket() {
auto packet = network->getPacket();
auto data = packet->decrypt();
switch (data->getType()) {
case PACKET_HEALTH_CHANGE:
onHealthChange(data->getMessage());
break;
case PACKET_MANA_CHANGE:
onManaChange(data->getMessage());
break;
// 更多数据包类型的更多 case
}
}
清单 10-2:游戏解析数据包的简化视图
任何特定游戏的确切代码可能不同,但控制流总是相同:接收数据包、解密、决定它包含什么类型的消息,并调用知道如何处理它的函数。一些游戏黑客拦截原始网络数据包,并在机器人中复制这个功能。这种技术有效,但需要广泛的加密知识、完整理解游戏如何在数据包内存储数据、中间人攻击网络连接的能力,以及定位游戏客户端正在使用的解密密钥的方法。
钩住负责在数据包解密和解析后处理它们的函数是更好的方法;在清单 10-2 中,这些函数是 onHealthChange() 和 onManaChange()。这种方法利用游戏处理数据包的内在能力,让机器人可以不知道游戏使用的各种网络设施。它还让你可以决定拦截哪些网络数据,因为你只需要钩住满足需求的处理程序。
注 拦截整个数据包有时可能有优势——例如,任何使用 Adobe AIR 并通过 RTMPS 通信的游戏。由于 RTMPS 有大量文档,无需逆向格式或加密。第 8 章详细解释了如何钩住 RTMPS。
有几个技巧可以让你轻松找到解析器函数,最终找到把数据包分发给处理程序的 switch() 语句。我发现最有用的方法是在游戏用来从网络接收数据的函数上设置断点,然后在断点命中时分析应用程序的流程。
让我们走一遍如何在 OllyDbg 附加到目标游戏时做到这一点。在 Windows 中,recv() 是从套接字接收数据的 API 函数。从 OllyDbg 命令行,你可以输入 bp recv 命令在 recv() 上设置断点。断点命中时,你可以用 ctrl-F9(执行到返回的快捷键)和 F8(步过的快捷键)爬升调用栈。这个组合基本上让程序执行到被调用者返回调用者,让你能随游戏一起爬升调用栈。在每个栈级别,你可以检查每个调用者的代码,直到找到一个有大 switch() 语句的;这应该就是数据包解析器。