如何让一个二进制可执行程序同时在Windows与Linux下原生启动?

发布时间:
2024-10-21 10:28
阅读量:
2

有同学说过 APE 了。

actual portable executable 依旧是个 windows PE 格式文件,只是利用了 Unix 在不清楚一个可执行文件该如何打开的时候会当作 POSIX shell 执行的特性。


比如 安装 mono 后:

sudo less /proc/sys/fs/binfmt_misc/CLR

enabled

interpreter /usr/bin/mono

flags:

offset 0

magic 4d5a


那么遇到 MZ (0x4d 0x5a) 开头的 windows PE 文件就会使用 mono 执行。

wine 也是同理。 你也可以配置遇到 windows PE 文件用 wine 打开。例如下图的 python.exe 在 Linux 上运行:

而对于没有配置用 wine 或 mono 打开 windows PE 文件的 Linux 系统, APE 会被当成 POSIX shell 执行。妙就妙在他还真是一个合法的 POSIX shell 。。。

当然你如果配置了 windows PE 打开方式,你就要再额外配置 APE 打开方式了。 magic 就不是 MZ 而是 MZqFpD 。

不过我想补充的一点是:

APE 格式文件利用的 Unix 会把一个文件当 POSIX shell 脚本执行的技巧也有别的使用场景。例如我就经常写这样的 C 示例代码:

#if 0 bin="$(basename "$0")" && bin="${bin%%.*}" && cc -g -Wall -o"$bin" "$0" && exec ./"$bin" "$@" || exit #endif #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { printf("hello\n"); return EXIT_SUCCESS; }


chmod +x main.c ./main.c


这里的 main.c 也会作为一个可执行文件,执行会会编译自己得到一个 main 文件,再执行 main 输出结果。第一行会被当场 POSIX shell 的注释直接忽视。这样把编译命令和代码写在一起有时怪省事的。唯一美中不足的是没有 shell 的语法高亮。。。(实现不了,因为就算在 tree-sitter 里写 query 匹配这个 AST 节点再 injection bash 的高亮,也会因为 #if 0 被 LSP 当成注释,除非改 clangd 的代码)


就酱紫。

END