XOR 加密(来自 Crypto 的 XPost)

逆向工程 异或
2021-07-02 15:36:56

亲爱的逆向工程@ SE

背景信息: 我有理由相信我玩过的一个老游戏仍然对几乎所有的输入/输出数据包使用他们的 XOR 加密。我还相信,当我分析数据包数据时,加密方案中使用的密钥保持静态,至少某些值的频率表明如此。

我知道以前的密钥是长度为 9 字节的 ASCII 密钥

问题: 我无法解密包。我尝试过直接循环密钥,对 TCP 包中包含的数据进行异或运算,还尝试了以下用于 XOR 加密的 C# 函数(请参阅附录)。

假设要使用 Vigenere 密码作为基础,前面的密钥表明长度可能是 9 个字符。

因为我可以在游戏中使用聊天功能,所以我确实可以完全控制解密包的明文(在这种情况下为 ASCII)将包含的内容。因此,我尝试发送相同的消息并观察 Wireshark 中的数据差异,如下所示:

游戏中发送的明文:

测试TheKeyTestingTheKeyTestingTheKeyTestingTheKey

以下快照是同一消息的三个数据包。注意长度如何保持不变,进一步指示静态密钥长度:

概览 (3 个点表示数据流量)

数据并排突出显示非标题数据

最后:相同数据包的十六进制转储。(见附录)

我对密码学比较陌生,但发现该领域非常有趣,希望有好心人愿意提供一些帮助。任何事情都值得赞赏。

谢谢你。

附录代码 http://pastebin.com/F0py05Lz

十六进制转储(由于低代表)

0000   aa 00 41 0e ad ce ff ce f0 ef e9 a0 f1 f8 9b a2
0010   fe df f8 e5 9c fb ed b8 a0 f6 f0 ca f7 ae d6 f8
0020   b4 9c fc e5 eb f7 a4 fb c8 a2 aa d5 f4 e1 cd a8
0030   e8 ef a2 a0 f8 c4 f1 fd 87 ff e3 c8 c3 e2 99 42
0040   de 51 ef 2b

0000   aa 00 41 0e ae 9a a8 ca f2 eb bf a3 a1 aa cf f5
0010   fa dd fc b3 9f ab bf ec f7 f2 f2 ce a1 ad 86 aa
0020   e0 cb f8 e7 ef a1 a7 ab 9a f6 fd d1 f6 e5 9b ab
0030   b8 bd f6 f7 fc c6 f5 ab 84 af b1 9c 94 d9 fd 32
0040   91 07 59 ba

0000   aa 00 41 0e af 9b fe 9a f9 e8 e3 f1 f2 a9 ce a3
0010   aa d6 ff ef cd f8 bc ed a1 a2 f9 cd fd ff d5 a9
0020   e1 9d a8 ec ec fd f5 f8 99 f7 ab 81 fd e6 c7 f9
0030   eb be f7 a1 ac cd f6 f7 d6 fc b2 9d c2 3f 2d 7a
0040   bd f6 42 d6
1个回答

为您的三个消息的关键似乎是cf7810d2242096edac4ea34873a分别。(注意:那些是 9 字节 ASCII 文本字符串,而不是十六进制数字,尽管很明显所有字符似乎都是十六进制数字!)


好的,那我是怎么想出来的?

首先,在查看您发布的代码之前,我只是从您的十六进制转储中获取消息,将它们转换回二进制(使用快速 Perl 脚本),并将它们异或在一起。生成的异或消息如下所示:

$ perl -0777 -E '$a = <>; $b = <>; print $a ^ $b' packet1.dat packet2.dat | xxd
0000000: 0000 0000 0354 5704 0204 5603 5052 5457  .....TW...V.PRTW
0000010: 0402 0456 0350 5254 5704 0204 5603 5052  ...V.PRTW...V.PR
0000020: 5457 0402 0456 0350 5254 5704 0204 5603  TW...V.PRTW...V.
0000030: 5052 5457 0402 0456 0350 5254 573b 6470  PRTW...V.PRTW;dp
0000040: 4f56 b691                                OV..

像这样对密文进行异或会消除明文(假设它在两个消息中相同),只留下密钥的异或。我们可以看到 XOR 数据中有一个明确的重复 9 字节模式,强烈表明消息确实已使用重复的 9 字节密钥加密。

现在,如果这是所有的,我们可以简单地通过采取已知明文字符串,找到问题的关键TestingTheKeyTestingTheKeyTestingTheKeyTestingTheKey,在不同位置上的密文进行异或它(因为我不知道究竟在何处已知明文会发生加密的消息),并期待对于看起来像一个似是而非的关键的结果。在加密术语中,这种方法被称为婴儿床拖拽,这个术语至少可以追溯到二战期间的布莱切利公园

唉,当我尝试这样做时,它没有产生任何看起来像重复的 9 字节文本字符串的东西,正如我预期的那样。事实上,输出中几乎没有任何可打印的 ASCII 字符。更仔细地观察密文,我注意到它的大部分字节都设置了高位,这在将两个 ASCII 字符异或在一起时不会发生。很明显,肯定还有其他事情发生。

那时,我仔细查看了您的(大概是以前逆向工程的)解密代码,并意识到它实际上将消息与三个不同的字节流进行了异或

  1. 重复的 9 字节密钥(从第六个字节开始应用),
  2. 密文的第五个字节(Incrementor,大概是某种消息计数器;这就是导致每个字节的高位被设置的原因,因为在您的消息中,它的值从0xADto 0xAF),应用于每个后续字节,以及
  3. 一个字节值 ( KeyVal),从零开始,每次密钥重复时递增 1,即第六个字节之后的每第九个字节。

(如果KeyValequals代码也跳过第 3 步Incrementor,大概是为了防止最后两个步骤相互抵消。这个小怪癖实际上几乎没有加密意义,无论如何,对于这些具有高Incrementor值的短消息,它永远不会发生.)

现在,方便的是,XOR 操作,就像加法一样,是可交换的和关联的——也就是说,如果你将两个或更多字节放在一起,那么你执行的顺序并不重要:(A XOR B) XOR C == A XOR (B XOR C) == A XOR (C XOR B) == (A XOR C) XOR B == ...因此,由于我知道Incrementor每条消息值(因为它是加密消息中给出的)并且对重复密钥长度(让我计算KeyVal每个字节)有一个非常可靠的猜测,我可以将每个加密字节与这两个字节进行异或值,留给我只是明文异或与重复键。

之后,通过crib-dragging很容易发现已知的明文字符串实际上在加密部分开始后的两个字节(因此在整个消息开始后的七个字节)开始,并获得9字节的密钥对于每条消息。

仅从您的三个示例消息中无法判断这些 9 字节密钥字符串实际上是如何生成的,或者游戏如何知道与给定消息进行 XOR 的密钥字符串。为此,您可能需要分析更多消息包,看看你是否可以找到任何类型的密钥模式。)