解码 CS:GO 与 PHP 匹配的共享代码

Decode a CS:GO match sharing code with PHP

我正在尝试构建一个解码 CS:GO 匹配共享代码的函数。我已经看过足够多的示例,但所有内容都在 JS 或 C# 中,但在 PHP.

中什么都没有

我以akiver demo manager为例,并试图在PHP中复制它。我有点盲目,因为我不知道某些点的输出是什么,所以我只能希望结果是我所期望的。我认为我走在正确的道路上,当字节必须 created/interpeted/converted 达到期望的结果时就会出现问题。

应解码的代码如下:'CSGO-oPRbA-uTQuR-UFkiC-hYWMB-syBcO'$getNextGame变量)

结果应该是3418217537907720662

到目前为止我的代码:

 /**
 * @param $getNextGame
 * @return array
 */
 public function decodeDemoCode(string $getNextGame): array
 {
     $shareCodePattern = "/CSGO(-?[\w]{5}){5}$/";
     if (preg_match($shareCodePattern, $getNextGame) === 1) {
        $result = [];
        $bigNumber = 0;
        $matchIdBytes = $outcomeIdBytes = $tvPortIdBytes = [];
        $dictionary = "ABCDEFGHJKLMNOPQRSTUVWXYZabcdefhijkmnopqrstuvwxyz23456789";
        $dictionaryLength = strlen($dictionary);

        $changedNextGame = str_replace(array("CSGO", "-"), "", $getNextGame);
        $chars = array_reverse(str_split($changedNextGame));
        foreach ($chars as $char) {
           $bigNumber = ($bigNumber * $dictionaryLength) + strpos($dictionary, $char);
        }
     }
 }

这让我想起了类似的事情:

1.86423701402E+43 (double)

那么我有以下内容:

$packed = unpack("C*", $bigNumber);
$reversedPacked = array_reverse($packed);

这带来了以下结果:

array(17 items)
   0 => 51 (integer)
   1 => 52 (integer)
   2 => 43 (integer)
   3 => 69 (integer)
   4 => 50 (integer)
   5 => 48 (integer)
   6 => 52 (integer)
   7 => 49 (integer)
   8 => 48 (integer)
   9 => 55 (integer)
   10 => 51 (integer)
   11 => 50 (integer)
   12 => 52 (integer)
   13 => 54 (integer)
   14 => 56 (integer)
   15 => 46 (integer)
   16 => 49 (integer)

现在我真的不确定该怎么做,因为我不完全理解 C#,而且我以前从未使用过 PHP 中的字节。

通常 return 类型应该是一个数组,看起来像这样:

$result = [
   matchId => 3418217537907720662,
   reservationId => 3418217537907720662,
   tvPort => 55788
];

提前致谢。非常感谢任何帮助

我创建了一个 PHP class 这使得这成为可能:

CS:GO ShareCode Decoder PHP

您必须解决的第一个问题是 returned double 值。 PHP 对于大整数有限制。更多信息请参见 What is the maximum value for an integer in PHP.

由于此限制,您正在失去精度,从而导致结果不准确。为了解决这个问题,您将不得不使用这些库之一 GMB, BC Math。这些库所做的是将结果作为 string 返回给你,它解决了你得到的双精度值。

因此您的代码必须如下所示:

foreach ($chars as $char) {
      $bigNumber = gmp_add(
         gmp_mul($bigNumber,$dictionaryLength),
         strpos($dictionary,$char)
     );
}
json_encode($bigNumber);
$result = json_decode($bigNumber, true, 512, JSON_BIGINT_AS_STRING);

这会给你以下"18642370140230194654275126136176397505221000"

您实际上不需要 PHP pack and unpack 函数,因为没有它们也可以生成结果。下一步是将您的数字转换为十六进制。您可以通过以下方式做到这一点:

$toHex = gmp_strval(gmp_init($number, 10), 16);

同样,您需要使用 gmp 库才能获得所需的值。您要做的是确保结果是一个字符串,然后将数字的基数从 10 转换为 16,这相当于十六进制。结果如下:

"d6010080bdf26f2fbf0100007cf76f2f5188"

下一步是将十六进制值转换为字节整数数组。它看起来像这样:

$bytes = [];
$byteArray= str_split($toHex, 2);
foreach ($byteArray as $byte) {
    $bytes[] = (int)base_convert($byte, 16, 10);
}

你在这里所做的是将数组拆分为每两个字符。 $byteArray 变量看起来像这样(在进入 foreach 循环之前)

array(18 items)
   0 => 'd6' (2 chars) 1 => '01' (2 chars) 2 => '00' (2 chars) 3 => '80' (2 chars)
   4 => 'bd' (2 chars) 5 => 'f2' (2 chars) 6 => '6f' (2 chars) 7 => '2f' (2 chars)
   8 => 'bf' (2 chars) 9 => '01' (2 chars) 10 => '00' (2 chars) 11 => '00' (2 chars)
   12 => '7c' (2 chars) 13 => 'f7' (2 chars) 14 => '6f' (2 chars) 15 => '2f' (2 chars)
   16 => '51' (2 chars) 17 => '88' (2 chars)

现在您必须将每个条目转换为整数。由于结果不再那么大,您可以使用 base_convert 函数更改值的基础。基数是 16(十六进制),您必须将其改回 10。foreach 循环后的结果 $bytes 如下所示:

array(18 items)
   0 => 214 (integer) 1 => 1 (integer) 2 => 0 (integer) 3 => 128 (integer)
   4 => 189 (integer) 5 => 242 (integer) 6 => 111 (integer) 7 => 47 (integer)
   8 => 191 (integer) 9 => 1 (integer) 10 => 0 (integer) 11 => 0 (integer)
   12 => 124 (integer) 13 => 247 (integer) 14 => 111 (integer) 15 => 47 (integer)
   16 => 81 (integer) 17 => 136 (integer)

现在您必须定义哪些字节负责每个结果。

$matchIdBytes = array_reverse(array_slice($bytes, 0, 8));
$reservationIdBytes = array_reverse(array_slice($bytes, 8, 8));
$portBytes = array_reverse(array_slice($bytes, 16, 2));
  • 对于匹配 ID,您必须获取前 8 个条目并反转数组
  • 对于预订 ID,您必须从第 8 个条目开始获取接下来的 8 个条目并反转数组
  • 对于端口,您必须获取最后 2 个条目并反转数组

现在您必须 return 值

  return [
       'matchId' =>  $this->getResultFromBytes($matchIdBytes),
       'reservationId' => $this->getResultFromBytes($reservationIdBytes),
       'tvPort' =>  $this->getResultFromBytes($portBytes)
  ];

getResultFromBytes()函数:

 **
 * @param array $bytes
 * @return string
 */
 public function getResultFromBytes(array $bytes): string
 {
    $chars = array_map("chr", $bytes);
    $bin = implode($chars);
    $hex = bin2hex($bin);
    return gmp_strval($this->gmp_hexDec($hex));
  }

 /**
 * @param $n
 * @return string
 */
public function gmp_hexDec($n): string
{
    $gmp = gmp_init(0);
    $multi = gmp_init(1);
    for ($i=strlen($n)-1;$i>=0;$i--,$multi=gmp_mul($multi, 16)) {
        $gmp = gmp_add($gmp, gmp_mul($multi, hexdec($n[$i])));
    }
    return $gmp;
}

此致