1.3、重写代码

Alex在讲述自己的杰作时颇为得意:“我们是程序员,对自己的东西了如指掌,我们明白代码中的数字如何对应机器中的扑克牌,然后我们就重写了一段C语言代码,与该型号机器完成同样的事情。”他说道。他们是使用C语言编写的程序。

我们的兴趣被强烈地激发起来,我们夜以继日地赶工。我敢说在两三个礼拜的时间里,我们就找到并掌握了代码运行的机理。

你看到它,从而做出一些推测,再写出一些新的代码,将它写到只读存储器(计算机芯片)中去,再将它放入到机器中,然后等着看会发生什么事情。我们可以做一些诸如编写程序的试验,这些程序能在计算机屏幕上的扑克牌背面显示十六进制数字。所以我们基本上得到一些如何处理扑克牌的设计规则。

我们使用了试错法和自上而下分析相结合的办法,这样就很容易理顺程序所表示的意义。所以我们也就彻底搞清楚了机器内部的数字是如何与屏幕上的扑克牌关联在一起的。

我们希望程序里的随机数的产生能够简单一些。在20世纪90年代初,情况的确如此。我稍微研究了一下,发现这些程序基于Donald Kunth早在60年代所提出的一种方法。这些家伙没有一点自己的创新,他们仅仅是将别人现有的成果套上Montecarlo方法,然后就填入了自己的代码。

我们猜得对极了,他们就是用这种算法来发牌的,这就是所谓的“线性反馈移位寄存器”,这是产生随机数的一种比较好的算法。

但他们随即发现这个随机数生成算法有个致命的漏洞,这样使得他们的工作更加简单了。Mike解释说这是一个相对简单的32位随机数字生成器,所以攻击其他系统程序的计算复杂度也在可接受的范围之内了。经过一系列的优化之后,程序变得更加简单。

因此这样产生的随机数并非真正意义上的随机数。Alex给出之所以出现这种状况的一个解释:

如果数字真的是随机的,投注赔率根本无法设置。他们无法知道确切的赔率是多少。有时一些机器可能会按照某种规律产生同花大顺,然而这根本不应该出现。因此一些设计者希望能够证明自己的设计能产生随机的数椐,或者证明他们没有控制游戏的结果。

设计者们设计机器时另一个没有意识到的问题是,其实他们所需要的并不是随机数生成器。一般来说游戏中的每一局会发10张牌,首先发5张,然后玩家观察手中的牌,如果他决定换牌,就先扔袢一张牌,再得到一张替换的牌。可以一直换牌,直到10张牌全部发完。在这种机器的早期版本中,这10张牌通常是通过随机数生成器一次产生的。

因此Alex和他的伙伴认识到这种早期游戏机的程序指令编写得非常蹩脚,当看到这些错误时,他们觉得自己可写一个更简单却更灵活的运算程序来攻击现有的程序。

在Alex看来,他们得先在赌场玩玩,看看那里机器上首先发的是哪5张牌,然后将这些数据输入家里的计算机上,计算机认清了这些牌之后,运算重写后的程序,计算出程序运行到什么位置,从而计算出再产生多少个数字会出现同花大顺。

因此我们测试了这台机器,让它运行我们的一些小程序,它准确无误地告诉了我们将要产生的扑克牌顺序,这让我们兴奋得不得了。将这种兴奋归结于“知道自己比别人聪明,能打败他们,而且还能从中捞一笔钱。”

在商场购物时,他们看到了一种娱乐场所用的倒计时腕表,时间能精确到0.1秒。他们立马买了三只——去赌场的每人一只。Larry将呆在家里操作计算机。

现场演练的准备都已就绪了。兵分两路:一路人马到赌场去玩牌,5张牌发完后,将自己手中牌的点数和花式都告诉Larry。Larry就将这些数字输入到他们自己的计算机。

这台杂牌计算机,融合了菜鸟与行家的智慧,它内部芯片的运行速度比日本生产的视频扑克牌游戏机快得多。因此用在这上面真是太适合不过了,仅花片刻功夫就计算出了赌场计时器开始倒计时的精确时间。

当倒计时结束时,在老虎机旁的这些家伙就按下“开始”按钮,但这个动作必须在一秒钟之内完成,要非常之准。但正如Alex解释的那样,问题没有想像的那样复杂:

“我们其中的两个曾是音乐家,如杲你也是的话,就会对节奏特别敏感,能在大约0.005秒内按下一个键。”

如果事情如预期发展下去的话,将会出现他们久候的同花大顺,他们在自己的机器上不断试验练习,直到每个人都可以以高命中率击中同花大顺。

前几个月的时间,用Mike的话说就是“更换机器的运算程序,明确知道随机数字怎么变成屏幕上的扑克牌,随机数字生成器以什么效率和什么方式产生一次结果。掌握了这种机器的‘癖好’,根据这些编写了一种将各种变数都考虑在内的程序。因此在某个特定的时刻,只要我们知道了一台机器当前的运行状态,我们就可以有把握地预测出接下来几个小时甚至几天内任何时候生成器的运行状态。”

他们打败了这台机器——将它变成了自己的奴隶,经受住了黑客要经受的挑战,并且胜出了。知识能帮他们赚到大钱。白日梦确实挺吸引人,他们能否美梦成真呢?