带有服务器端检查的反向数据包加密

逆向工程 艾达 拆卸 部件 ollydbg 调试
2021-07-08 11:49:19

我制作了一个挂钩 MMORPG 游戏发送功能的 DLL。send()函数被调用时,它会循环发送数据包,直到我停止它,而不是只发送一次数据包。

我的问题是数据包是加密的。并且,服务器检查从客户端发送的每个数据包。如果服务器期望的数据包与客户端发送的数据包不匹配,服务器将断开您的连接。因此,即使您在客户端禁用加密代码,它仍然会在服务器端得到验证。

我设法通过修改二进制文件来禁用数据包的加密,但由于上述语句,我仍然断开连接。而且,我不能无限循环发送它,因为每个数据包都应该不同。

信息:

  • 只有从客户端发送到服务器的数据包被加密。从服务器到客户端的数据包没有加密。
  • 只有数据包的前 2 个字节被加密。剩下的8个字节不是。数据包的大小为 10 字节。
  • 我找到了函数(用汇编编写),它生成用于加密前 2 个字节的动态密钥。我想使用这些代码,但我不知道如何将它们翻译成更高级的语言,如 c++。

解密函数

unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) {
  if (sd) {
    return (cmd ^ ((sd->cryptKey >> 16) & 0x7FFF));
  }
  return (cmd ^ ((((clif->cryptKey[0] * clif->cryptKey[1]) + clif->cryptKey[2]) >> 16) & 0x7FFF));
}

问题:

  • 如果服务器检查每个数据包,我如何实现以无限循环发送数据包的目标?
  • 我应该在每次发送之前使用加密前两个字节的函数吗?
1个回答

首先声明

如果服务器期望的数据包与客户端发送的数据包不匹配,服务器将断开您的连接。

没有意义。

服务器如何知道您要发送给他的内容?
也许您会注意到如果数据包格式错误(更改数据包的结构 - 或者,例如,通过禁用数据包加密 - 在这种情况下,服务器将尝试解密它并会得到不可解释的结果),服务器会断开您的连接。

所以要回答你的问题:

IMO 你有两种可能的方法来实现你的目标:

  1. 找到在加密之前创建数据包的函数,并使用它来发送您自己的数据。
  2. 了解您的游戏的网络协议和密码学是如何工作的,并在您自己的程序中重建它。

我建议您使用第一个选项,因为它更简单。虽然第二个选项为您提供了更大的灵活性,但我认为这对您来说不可行,因为您说but I don't know how to translate them into a higher level language like c++..

我只能为您提供一般说明,因为您没有发布有关目标的太多信息(名称、一些程序集片段,如果它使用 TCP 或 UDP,..):

  1. 使用动态调试器查找 #1 中提到的函数。我更喜欢x64dbg,因为它适用于 x86 和 x64 位应用程序。
  2. 在套接字发送函数上设置断点。使用哪个发送函数取决于您的游戏,但可能的候选函数是sendsendtoWSASendWSASendTo
  3. 通过在所有函数上放置断点来查找使用的发送函数,并观察哪个 bp 触发。现在您知道使用哪个函数将数据发送到游戏服务器了。我将WSASendTo在此示例中使用它,因为它在现代 udp 应用程序中非常常见(我假设您的游戏使用 UDP - 我可能是错的)。
  4. 正如您WSASendTo在函数的文档中知道的那样,将指向一个或多个WSABUF结构的指针作为第二个参数。通常它只是一个WSABUF
  5. 由于几乎每个 windows api 函数都是__stdcall第二个参数,[esp+0x8]当您的断点触发时([esp]是返回地址,[esp+0x4]是第一个参数_In_ Socket s)。
  6. 如果您使用 x64dbg,您现在可以按照指向WSABUF“转储中”结构的指针来查看它的内容。您还可以按照返回地址 at[esp]查找调用WSASendTo.
  7. 您可能需要重新启动游戏几次,并在调用 windows 发送函数的函数上设置新断点。
  8. 在某些时候,您会看到缓冲区的内容发生了变化——您说过只有前两个字节是加密的,因此您已经知道该注意什么了。
  9. 此时您应该知道哪个函数负责加密您的数据。也许这已经是你所需要的——也许你需要在调用层次结构中走得更高一些,才能找到真正启动整个packet create-encrypt-send过程的函数

希望有帮助!