C
发布于 2026/09/03 · 阅读 7

对《创:战纪》中shell历史场景的吹毛求疵

  • #Unix
  • #Shell
  • #电影技术细节
  • #系统管理
  • #Hacker News
对《创:战纪》中shell历史场景的吹毛求疵

引言

在2010年的电影《创:战纪》中,有一个场景是主角Sam Flynn坐在他父亲的书房里,在电脑前输入一些命令,试图找出Flynn Sr.失踪前最后在做什么。当我第一次看这部电影时(刚好有DVD),我暂停了画面,以便仔细查看电脑屏幕上的文本。我还能说什么呢?我就是那种极客。

《创》系列电影整体上基于一些完全荒谬的关于计算机工作原理的前提。所以我并不期望它会写实;更可能的是,我觉得那会是电影人编造出来的搞笑伪计算机术语废话。但实际上,我看到了一个几乎可信的Unix shell记录,其内容在电影情节的背景下是有意义的——尽管有几处细节立刻引起了我的注意。

今年,我想起了那个场景,并认为它可以成为给初级同事的一个很好的学习练习:让我们一起看那张静态图像,看看我们能从中理解多少。我们能找到所有明显的错误吗?忽略我们已确定是错误的东西,我们能从其余信息中推断出关于计算机系统以及Flynns(父子两人)用它做什么的信息吗?我希望这会有趣、有意思和/或具有教育意义。它在这三方面都超出了我的预期!我原本以为只需要半小时,结果我们断断续续地花了一整天(在Slack上交流信息,穿插在其他工作之间),从中榨取出的东西比我意识到的要多得多。到练习结束时,我最初的一个抱怨被证明是错误的(但找到了另一个来替换它),而且我自己也学到了一些新东西。最终,我对那个制作截图的人比开始时更加印象深刻。

所以,既然它变得如此有趣,这里有一份详细的记录,这样如果你和我一样是那种极客,你也可以分享这份乐趣!

剧透警告

这篇文章将包含电影中某个情节的轻微剧透。但它不会是你从看过1982年原版电影《创》后就不难猜到的东西。无论如何,即使《创:战纪》现在已经16岁了,而且之后又出了一部《创》电影,所以如果你在意剧透,你可能已经看过了。更重要的是,当我给我的同事布置这个练习时,它是作为一个教育谜题——重点是找出答案,而不是仅仅以讲座的形式听到答案。所以我会注意不破坏那个谜题。在本文中,我会展示我所有的答案,但它们都在<details>折叠下面,这样你可以在点击之前自己检查记录,看看自己能从中得到多少信息。

截图

当然,我必须先展示电影中的一张静态图像。我的理解(虽然我不是律师)是,这在版权法下应该是合理的。然而,我当然没有能力与迪士尼进行一场严肃的法律斗争,所以如果他们要求我删除图片,我将别无选择。

文本前面的污迹和后面不均匀的背景颜色是因为屏幕是一个反射性的桌面表面,上面覆盖着一层厚厚的灰尘,直到刚才;在Sam坐下之前,我们看到他把一些灰尘擦掉了。当Sam到达时,右侧的主shell窗口是空的。这里显示的所有内容都是他刚刚自己输入的命令,以及计算机对这些命令的响应。

文本转录

我手动打出了这些内容,这样你就不必看了:这里是那个主shell窗口中的会话文本转录。

$ whoami
flynn
$ uname -a
SolarOS 4.0.1 Generic_50203-02 sun4m i386 Unknown.Unknown
$ login -n root
Login incorrect
login: backdoor
No home directory specified in password file!
Logging in with home=/
# bin/history
488 cd /opt/LLL/controller/laser/
489 vi LLLSDLaserControl.c
490 make
491 make install
492 ./sanity_check
493 ./configure -o test.cfg
494 vi test.cfg
495 vi ~/last_will_and_testament.txt
496 cat /proc/meminfo
497 ps -a -x -u
498 kill -9 2207
499 kill 2208
500 ps -a -x -u
501 touch /opt/LLL/run/ok
502 LLLSDLaserControl -ok
1 #

我们能从这张截图中观察到什么?

如果你愿意亲自尝试这个练习,请仔细观察上面的图像,看看你能发现什么。准备好了,点击下面的剪切,你会看到一系列要考虑的话题。如果这些给了你有用的提示,你有机会在逐一打开每个话题之前更深入地思考每一个问题,然后看到我们对此的看法。

话题列表

打印shell历史的命令

这是我第一次看这部电影并暂停DVD时首先注意到的事情。Sam通过运行bin/history而不是简单的history来请求shell历史。为什么?我想不出任何在真实Unix上可能有意义的方式。Shell历史存储在shell进程内部的数据结构中,所以history命令必须是内建命令才能读取这些结构。即使你只想读取存储在磁盘文件中的历史版本,该文件的名称和位置也因shell及其配置而异,因此一个外部命令要做到这一点仍然非常困难。

我当时的结论——现在仍然觉得相当合理——是这揭示了电影制作人呈现他们伪造的情节相关shell历史所采用的技术。(就像wire-fu中偶然可见的钢丝。)我认为这个shell会话是通过在真实、仔细配置的Unix机器上输入命令生成的,而bin/history是一个简单的shell脚本,它打印出那段历史,替代了真实shell中更无聊的东西。(特别要注意,历史记录并没有以bin/history命令结束!当你运行真实的shell历史命令时,通常输出结束于你刚刚输入的那个历史命令,因为它已经被插入到历史列表中,然后历史列表被读取回来。)

假设我没错,这可以做得更好:用别名或函数包装history shell内建命令。那样用户就可以输入普通的history,但仍然能产生这个精心构造的输出。(同样的论点不适用于Sam在这个会话中输入的其它命令,比如uname,因为它们不是shell内建命令:它们是在PATH上找到的,所以你可以通过将自己的目录放在PATH前面来覆盖它们。所以我的猜测是,设置这个场景的人知道怎么做那个,但不知道怎么做别名。)

计算机上的账户设置

Sam首先看到的是一个shell提示符,而不是登录提示符:Flynn已经登录了。所以他先运行whoami来确定他以什么身份登录。计算机打印出flynn,大概是一个非特权用户账户。这不好——Sam知道他需要成为root才能正确调查。他试图以root身份登录,但失败了,于是他尝试了backdoor,成功了。

一个自然的问题是:如果root和backdoor是不同的账户,他岂不是要列出错误账户的shell历史?Flynn肯定是以root身份做他正在做的事情。但我们可以看到,backdoor账户的用户ID是0,与root相同,因为在Sam成功以backdoor登录后,shell提示符从$变成了#。这通常发生在shell检测到它正在以root uid运行时。所以backdoor和root共享一个uid,因此合理地猜测它们也共享一个主目录和shell历史。

我们还看到,backdoor的主目录被login设置为VFS根目录/,因为在/etc/passwd中没有指定更好的目录。所以大概shell从VFS根目录读取了一个历史文件:类似/.bash_history,或者至少/.something_history(我认为没有太多证据表明这具体是什么shell)。root的主目录也设置为/是相当合理的;这在Linux上不是默认的,Linux给root一个自己的主目录,但在我在1990年代使用的专有Unix上这非常常见。所以这一切都说得通:Flynn以root身份运行了那些命令,通过一个稍微绕弯的路径,Sam可能确实登录到了一个能以自然方式列出这些命令的账户。

(我也对在现有登录会话中使用login切换用户有点怀疑;人们可能期望用su?要完成这项工作,/bin/login需要是setuid的,而在Linux上它当然不是——它期望由像getty或(历史上)telnetd这样的程序调用,这些程序在运行时已经是root。也许Solaris(或SolarOS)不同?但似乎不太可能。)

最后,为什么会有backdoor账户?通常,如果你有对系统的访问权限但担心有人会试图剥夺这种访问权限(而且你是不道德的),你会创建一个这样的账户。一个担心原始入口会被切断的黑客,或者一个拥有系统root权限的人,担心其他人会剥夺他们的访问权限。在这种情况下,这是Flynn自己的机器;他预期谁会把他锁在外面,以至于需要一个后门重新进入?我们可以简单地归因于编剧的捷径:有时系统有后门,所以如果情节需要,你可以假设有一个,而不需要提供世界内的解释。但在这次练习中,我们大多不必使用那种非答案,所以我宁愿不这样做。我认为一个完全合理的世界内解释是Sam在父亲不知情的情况下制造了后门。也许Flynn信任他的儿子,让他在这台机器上拥有root权限(合理——我的父亲信任我,当我们共享一个Linux系统时),但Sam有理由怀疑Flynn变得隐秘和神秘,并预见到Flynn可能会关闭root账户以试图隐藏他在做什么。而且看起来这确实发生了,因为我们可以看到Sam最初期望能够以真正的root身份登录,只有在发现不能时才使用了后门。显然他非常了解父亲,怀疑得没错!

这到底是什么Unix风味?

Sam运行的另一个初步调查命令是uname -a,以检查他面对的是哪种Unix系统。你可以想象,如果他是一个足够了解Unix的通才,知道哪些操作系统在哪些细节上有所不同,那可能会改变他后续输入命令的选择。

uname打印的操作系统名称是“SolarOS”。这不是一个真实的操作系统名称,但它看起来很像是SunOS和Solaris的混合体,这是Sun Microsystems专有Unix系列的两个名称。我推测名称的微小改动可能是故意的,以避免Sun的商标问题?uname输出中后来出现的sun4m支持了这一理论。而且uname字符串的整体格式与我找到的网页上的真实Solaris示例非常接近(唉,我无法访问真正的Solaris机器来确认)。

后面的i386表明这是x86架构,Unknown.Unknown可能是主机名或类似的东西。但值得注意的是,Solaris通常运行在SPARC上,而x86版本也存在,所以这并不矛盾。

命令序列

让我们看看历史记录中的命令。它们似乎展示了一个合理的开发工作流程:

488 cd /opt/LLL/controller/laser/ 489 vi LLLSDLaserControl.c 490 make 491 make install 492 ./sanity_check 493 ./configure -o test.cfg 494 vi test.cfg 495 vi ~/last_will_and_testament.txt 496 cat /proc/meminfo 497 ps -a -x -u 498 kill -9 2207 499 kill 2208 500 ps -a -x -u 501 touch /opt/LLL/run/ok 502 LLLSDLaserControl -ok

首先,路径/opt/LLL/controller/laser/暗示了一个名为“LLL”的软件包,很可能代表“Laser Light Laser”或类似的东西(考虑到电影中的激光主题)。代码文件LLLSDLaserControl.c可能是一个SDL(Simple DirectMedia Layer)激光控制程序。然后他进行了makemake install,运行了sanity_check(可能是个测试),然后他配置了一个测试配置文件(./configure -o test.cfg),并编辑了它。接着他编辑了一个名为~/last_will_and_testament.txt的文件(这听起来很戏剧化,可能是电影情节的伏笔)。然后他检查了内存信息(cat /proc/meminfo),列出了进程(ps -a -x -u),杀死了两个进程(PID 2207和2208),再次列出进程确认,最后创建了一个标志文件/opt/LLL/run/ok并以-ok选项运行程序。

注意,make install通常需要root权限,这解释了为什么Flynn以root身份运行。另外,cat /proc/meminfo是Linux特有的(procfs),而Solaris使用prtconf或其他工具,但既然操作系统是“SolarOS”,可能它兼容Linux的procfs?或者这是故意的错误?我们稍后会讨论。

一个有趣的点是kill -9 2207kill 2208(不带-9)。通常kill默认发送SIGTERM(15),而kill -9发送SIGKILL。他先用了SIGKILL,然后用了SIGTERM,这有点奇怪:通常你会先尝试SIGTERM,如果不行再升级到SIGKILL。也许他故意先杀了那个顽固的进程?

另外,LLLSDLaserControl -ok命令看起来像是程序自身的选项,而不是一个独立的命令。可能./configure -o test.cfg生成了一个Makefile或可执行文件,然后他用-ok参数运行它。

历史命令的编号

历史记录显示了命令编号从488到502。这意味着在Flynn的shell历史中,之前还有487个命令。Sam只看到了最后15个左右。这很合理,因为历史文件通常保留最后N条命令。

但注意,bin/history命令本身并没有出现在历史记录中(因为它是手动的?)。而且历史记录以1 #结尾,这似乎是提示符?实际上,转录中的最后一行是1 #,这可能表示在Sam登录后,shell提示符变成了#,并且他输入了1?但历史记录显示的是Flynn的命令,而不是Sam的。所以1 #可能是一个伪影:也许在Sam运行bin/history后,shell显示了提示符,而1是下一个命令的开始?但Sam没有输入任何东西?有点混乱。

proc/meminfo

cat /proc/meminfo是一个特定的文件,在Linux上存在,提供内存信息。在Solaris上,通常通过prtconfkstat来查看内存信息。所以这可能是一个错误,或者“SolarOS”故意模仿了Linux。但既然电影中的系统看起来有点像Solaris(有sun4m),这可能是穿帮。

ps命令

ps -a -x -u:在Linux上,-a是“所有进程(包括其他用户)”,-x是“包括没有控制终端的进程”,-u是“以用户格式显示”。在Solaris上,ps的选项不同:ps -a -x -u可能不会产生相同的结果。例如,Solaris的ps使用-ef-aux(后者与Unix System V兼容)。所以这个命令看起来更像Linux风格。

kill命令

kill -9 2207kill 2208:在大多数Unix系统上,kill是标准命令。但注意,在历史记录中,它们是单独的行,没有输出。通常kill不会产生输出,除非有错误。所以这没问题。

touch和ok文件

touch /opt/LLL/run/ok创建一个空文件,可能是作为状态标志。然后LLLSDLaserControl -ok运行程序,-ok选项可能表示“如果ok文件存在,则运行”。

结论

总的来说,这个场景比我想象的要合理得多。虽然有一些小的错误(如bin/history、proc/meminfo的Linux特性、ps选项的风格),但整体上电影制作人做了一个令人印象深刻的努力,创建了一个看起来真实的Unix shell会话。作为极客,我们喜欢这种细节。《创》系列一直以其对计算机技术的独特诠释而闻名,而这个场景显示了对真实系统的相当好的理解,尽管有些艺术加工。

总结

通过这个练习,我学到了很多关于Unix shell历史、账户设置、不同Unix风味之间的差异以及电影制作人如何创造令人信服的假技术内容的知识。它也提醒我们,即使是小细节也能引发深入的讨论和学习。如果你还没有看过这个场景,也许现在是时候暂停一下电影,仔细看看那个屏幕了。你可能会发现更多有趣的东西!

7 阅读0 评论0 点赞

评论

登录 / 注册即可发布评论!
暂无评论,成为第一个发表评论的用户吧。