虚拟机的 Bash 脚本头

虚拟机的 Bash 脚本头

我有一个小编译器宠物项目,它为虚拟机生成字节码。要从终端运行生成的字节码,我总是必须使用生成的字节码文件调用虚拟机(通过svm my-binary-file,其中svm是 VM 可执行文件的名称)。因为我希望能够直接执行编译器生成的文件,所以我想出了以下解决方案:

我在生成的文件前面添加了几个 bash 命令,用于标识文件名(以解释用户重命名文件),使用该文件调用虚拟机并退出。这些是命令:

# Identify directory
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# Identify filename
FILENAME="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
# Invoke the virtual machine
svm "$SCRIPT_DIR/$FILENAME"
# And exit
exit $1
HERE COMES BINARY JIBBERISH...

每个命令上方的注释很重要,因为 VM 需要它们跳过 bash 命令进入二进制部分。编译器调用它们chmod +x <filename>来允许执行文件。

现在我可以直接用 运行生成的文件./my-binary-file。这一切都运行得很好,但我的问题如下:

由于我对 bash 一无所知,也不太熟悉 unix 和终端(我不得不在 Google 上搜索所有命令,基本上都是从 SO 上复制的),我想知道这个解决方案是否存在一些我不知道的明显缺陷或安全问题。毕竟这个解决方案感觉很不靠谱。

答案1

它是否有效完全取决于初始解释器。是的,它很老套,但其他任何方法都必然是特定于操作系统的解决方案。

如果 Bash 不介意脚本以垃圾结尾,那么这样做没问题。这种方法在 Tcl 脚本中很常见,有时 Tcl 脚本会像执行 tclsh 的 bash 脚本一样启动(而不是直接调用 tclsh,原因多种多样)。

(类似的技术也是 Perl 和 PHP 语言的一部分,其中整个脚本被解析,但你可以明确地告诉编译器停止__DATA__- 虽然在这种情况下,原始解释器Perl 或 PHP,它仅仅从脚本中读取数据负载。)

让它不那么容易被黑客攻击的方法是直接使用,"$0"而不是试图将其拆分并重新组合。通常,您不需要费尽心思去解析符号链接。

一种更受欢迎的机制Linux具体来说,就是通过“binfmt_misc”注册您的格式。确保可执行文件以您选择的独特“魔法数字”开头(即,明确标识您的格式的静态前缀;通常至少 4 个字节是个好主意)——教会您的 VM 运行时识别并在必要时跳过它,就像它目前跳过的那样#!/bin/bash——然后您可以配置 Linux 以接受此类文件作为可执行文件并在正确的解释器下自动运行它们。

例如,WASM 可执行文件以字节开头\0asm\1\0\0\0,因此如果你这样写

:wasm1:M::\x00\x61\x73\x6d\x01\x00\x00\x00::/usr/bin/wasmer_包装器

/proc/sys/fs/binfmt_misc/register(或放入/etc/binfmt.d/wasm.conf),现在您可以直接执行 WASM 程序:

$ ls -l main.wasm
-rwxr-xr-x 1 users 1.2K Feb  8  2023 main.wasm*

$ file main.wasm
main.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

$ head -c 16 main.wasm | hd
00000000  00 61 73 6d 01 00 00 00  01 17 04 60 01 7f 00 60  |.asm.......`...`|

$ ./main.wasm 
Hello, world!

相关内容