原文的pdf链接: https://www.ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf

这篇文章是1984年Ken Thompson获图灵奖时的演讲稿。

文章开始时提到,他早期与Dennis Ritchie (C语言的创始人,并且与本文作者Thompson一起开发了Unix系统) 一起工作时一直配合得很好。他能想起的协调不够好的只有一次:他们两人各自写了一段20行的一模一样的汇编代码。

他还提到,在他的1040表 (个人所得税退税表) 上,他自己的职业写的就是programmer。在那时候programmer这个职业可能会让人觉得奇怪。

这篇文章要展示的是他写的最机灵 (cutest) 的一个程序。整个故事分三阶段。

#第一阶段:自我复制程序

所谓自我复制程序,指的是这个程序运行起来后只做一件事,就是把自己的源代码显示在屏幕上。在Thompson的学生时代,还没得游戏玩,他们当时的一个娱乐就是比赛谁写的自我复制程序最短。

习题 用C, Python, Fortran, 或其它任何你擅长的语言写一个自我复制程序。

写过一些自我复制程序后就会发现:(1) 这种程序本身很容易由另一个程序写出(只是输出一个字符串而已)。(2) 这种程序里可以包含任意多的额外信息(比如注释),这些额外信息在程序运行时会被一并复制出来。

#第二阶段:鸡与蛋

C语言的编译器是用C语言写的,那么最开始是怎么编译的?答案:最开始结合了手工编译。 讲了如何让编译器接受新的特殊字符。

#第三阶段:特洛伊木马

这段讲了如何在编译器层面植入木马。

当编译器被调用时,检测输入字符串(每个程序都是一个字符串)是否匹配某个模式,如果匹配,则进行恶意编译。

作者说,他在植入木马时匹配的模式是Unix的login命令的代码。如果被编译的是login命令,则编译器实际编译的是被改过的login。这个被改过的login留了个后门,只要输入密码是某个特定的字符串就允许登录。

当然了,如果只是这样明目张胆的在编译器里植入后门,那么很容易被其他能阅读编译器源代码的人发觉。所以光这样还不够。

所以还需要关键一步:第二个木马。第二个木马针对的是编译器本身,替换的程序是一个自我复制程序,把两个木马插入到编译器中。这需要用到“鸡与蛋”的学习过程:先用正常的C编译器来编译被植入后门的编译器,然后把这个被植入后门的编译器作为官方编译器发布。然后,删除编译器源代码中的木马部分,这样其他人阅读编译器源代码时就不会知道有木马了。但是用那个被植入木马的编译器编译不包含木马的编译器源代码时,生成的可执行文件仍然包含木马。

#教训

教训就是,你不应该信任不完全是你自己创造的任何程序,特别是不应该信任雇佣了本文作者Thompson这种人的公司生产的软件,即便你能看到源代码也没用。前面针对的是C语言的编译器,但完全也可以针对汇编器、连接器、甚至硬件驱动做同样的事情。越是底层的代码越难发现这类问题。

作者强调,入侵他人的计算机系统跟入侵他人的房屋是一样的,都是非法的。

最后他说他起初是在一份美国空军的文档中看到实现这种木马的可能性的。