Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

整合包预启动命令(Pre-Launch Command) #13

Open
3 tasks done
3TUSK opened this issue Mar 28, 2024 · 28 comments
Open
3 tasks done

整合包预启动命令(Pre-Launch Command) #13

3TUSK opened this issue Mar 28, 2024 · 28 comments

Comments

@3TUSK
Copy link

3TUSK commented Mar 28, 2024

检查项

  • 我充分理解提交的建议可能无法所有启动器作者参与,并尊重所有启动器开发者的选择
  • 我确认在Issues列表中并无其他人已经提出过与此问题相同或相似的问题
  • 我确认该反馈并非针对单个启动器的,如果是,我将会去该启动器的反馈页面反馈

您是什么类型的用户

其他

请简单的说一下您的想法

允许整合包定义一串需要在游戏启动前运行一次的命令(通过当前系统的 Shell,或者说 exec 执行),并随整合包一并导出。

它能解决什么样的问题/带来什么样的帮助

Packwiz-Installer 为代表的一些整合包制作工具提供了基于 MultiMC 的 Pre-Launch Command 实现的整合包自动更新机制,以实现「每次启动游戏时,整合包内容即自动获得更新」。

若能实现该功能,整合包自动更新便可不依赖于特定的启动器而实现,由此给予用户更大的自主权,同时方便任何有「需要短时间内快速更新整合包内容」的服主无需为此自制启动器或相关基础设施。

期望的结果

在「MCBBS 整合包格式」中允许定义一可选新字段,名称待定,其内容为当前操作系统可执行的一串命令。启动器在读取到该字段后,会在每次启动游戏前尝试执行该命令。

命令的执行可以以 Java SE 标准库中的 java.lang.ProcessBuilder 为参考标准。

命令执行时,应以环境变量(Environmental Variable)或其他形式提供一些实用信息,包括但不限于

  • 当前整合包所用 Java 运行时入口程序的绝对路径
  • 当前整合包的游戏目录,即所谓的 .minecraft 目录,或者说 gameDir
  • 当前整合包的名字

考虑到以 java.lang.ProcessBuilder 为标准的话,未必会有各种主流 Shell 支持的环境变量展开,有必要明确一套「展开占位符」的约定。

是否有对这个方案的相关链接?

附注

这个建议实际上源自历届 TeaCon 中出现的永恒难题:在参展 Mod 及其他相关资源每天都有更新的情况下,如何应对整合包版本的快速迭代。
我们在 TeaCon 2021 和 2022 中使用了自制的 RemoteSync 来解决这一问题。虽然成功解决了版本快速迭代问题,但我们随后在两届 TeaCon 中发现了由此引发的更多问题,并最终促使我们在 TeaCon 2023 转向 Packwiz。

我曾尝试过其他可能的解决方案,例如使用 Java Agent 搭配 JVM Arguments 来实现类似效果,但我不确定该方案是否最终在 TeaCon 2023 中实装。

利用 Java Agent 的 premain 来更新整合包的想法并非只有我尝试过:在 ModFest 主办的 BlanketCon 23 中,其展示服务器客户端便使用了 unascribed 的 unsup 来实现整合包随游戏启动自动更新,原理即 Java Agent。

抄送 @ustc-zzzz

题外话:「MCBBS 整合包格式」有没有正式的名字和文档?

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

整合包内自定义指令的问题是:

  1. 当前环境不支持所使用的指令
  2. 容易被投放木马病毒

@3TUSK
Copy link
Author

3TUSK commented Mar 28, 2024

一些相关,但过于遥远且复杂的想法:

  • Mod 文件 PGP 签名检查。源自 Optional signature verification packwiz/packwiz-installer#63。TeaCon 自第一届(2020)起便自行构建所有参展 Mod,并自 2021 起对所有构建结果进行 PGP 签名,以确认这些文件来自 TeaCon 执行委员会。Fractureiser 事件之后,有部分社区成员提出「可以通过收集各开发者的公钥,并要求 Mod 文件均附带签名,来遏制恶意软件投放及传播」,惟该倡议因种种已有充分讨论的阻力而不了了之。
  • 三路合并配置文件。源自 Three-way merge configuration files packwiz/packwiz-installer#64。这是来自 TeaCon 2022 的真实问题:用户自行修改了某 Mod 的配置文件,且该参展 Mod 作者也修改了随包附带的配置文件,如何处理三份互不相同配置文件的 diff 合并?

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

我的建议是如果真的要做这个功能,设置指令前需要向用户弹窗确认

@zkitefly
Copy link

或许可以让启动器支持 MultiMC 整合包的 Pre-Launch Command 支持?

@3TUSK
Copy link
Author

3TUSK commented Mar 28, 2024

当前环境不支持所使用的指令

这个问题很有趣。
TeaCon 2023 所使用的 Packwiz 是基于 Kotlin 编写并以 JVM 作为编译目标的。Packwiz-Installer 利用了 MultiMC 的 Pre-Launch Command 执行时注入的 INST_JAVA 环境变量以获取「当前游戏启动时所用的 Java 程序的绝对路径」来运行 Packwiz-Installer-Bootstrap。由此,Packwiz 利用了 JVM 本身即跨平台的特性避免了「针对不同操作系统进行特殊处理」的问题。

不妨允许根据当前操作系统、CPU 架构等的不同来决定该执行哪一个命令。就像这样:

{
  "pre-launch-command": {
    "windows-amd64": "paint.exe",
    "macos-arm64": "say hello from macOS",
    "linux-loongarch": "uname -a"
  }
}

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

或许可以让启动器支持 MultiMC 整合包的 Pre-Launch Command 支持?

不,modrinth整合包并没有此功能,这个功能是MultiMC启动器的

@ustc-zzzz
Copy link

木马病毒的说法纯属无稽之谈:无论是整合包模组,还是整合包启动参数里的 Java Agent,在植入木马病毒的难度方面和预启动命令上没有显著差别,而一般用户也根本不会去逐个检查,换言之用户是因为信任的是整合包本身,而不是因为信任了整合包的哪些部件。既然用户已经信任了这个整合包,那么额外增加所谓的确认流程也不会让用户更加信任什么东西,而如果用户本来就不信任这个整合包,他也一定会额外检查这个预启动命令是否安全。

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

整合包模组一般是从modrinth或curseforge平台上下载的,可以避免多数注入

@ustc-zzzz
Copy link

当前环境不支持所使用的指令

另一个可能的解决方案是让启动命令默认为 java,整合包只记录启动参数(例如 ["-jar", "xxx.jar"]),可以在制作整合包的时候提供一些便利,当然也不需要关心跨平台的问题。

@ustc-zzzz
Copy link

整合包模组一般是从modrinth或curseforge平台上下载的,可以避免多数注入

用户可不会逐个检查整合包模组的链接是否真的来源于 cf 或者 modrinth,这个整合包格式也没有强制所有模组都从 cf 或者 modrinth 下载。

@burningtnt
Copy link

木马病毒完全就是无稽之谈。

我倾向于支持两大格式,pre-launch-command可以直接为一个命令,或为一个结构体,指明不同操作系统上的具体执行的命令。
而对于一个命令,可以是一个 string[],或直接是一个 string。前者可直接传入 ProcessBuilder 作为参数,后者则由启动器自行 tokenize 后再做处理。

这样,既可以保证支持不同平台执行不同命令的功能,也可以让跨平台命令更加方便执行。
同时,string 模式则提供较为简便的写法;string[] 模式则给予作者更多自由度,与启动器的 tokenize 算法解耦。

问题:目前绝大部分启动器均支持 INST_JAVA 环境变量。但环境变量插入的规则不同。
我倾向于使用 "$INST_JAVA" 的风格,但这样会导致:

  • 引入新的关键字 $
  • 无法确定环境变量末尾的位置

@zkitefly
Copy link

$INST_JAVA 的风格好像也是 MultiMC 的 Pre-Launch Command 风格

@Pigeon0v0
Copy link

Pigeon0v0 commented Mar 28, 2024

要做自动更新不如把 MCBBS 整合包格式 v2 的文档搞完了来,启动前执行命令风险太大了

@burningtnt
Copy link

要做自动更新不如把 MCBBS 整合包格式 v2 的文档搞完了来,启动前执行命令风险太大了

风险何在?如果我要投毒,随意往一个 JAR 里面塞点东西不是更好?何必一定要走启动前执行的命令呢?

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

要做自动更新不如把 MCBBS 整合包格式 v2 的文档搞完了来,启动前执行命令风险太大了

风险何在?如果我要投毒,随意往一个 JAR 里面塞点东西不是更好?何必一定要走启动前执行的命令呢?

不能因为另一件事情"也有风险"而否认一件事的风险

@zyxkad
Copy link

zyxkad commented Mar 28, 2024

相对于启动指令,jar的毒更容易被扫描,比如检测有无使用关键包,调用关键函数等

@ustc-zzzz
Copy link

相对于启动指令,jar的毒更容易被扫描,比如检测有无使用关键包,调用关键函数等

JVM 又不是沙箱,Jar 内部也可以执行命令,关键包/关键函数又从何谈起?启动命令直接以文本形式写入整合包配置,而 Jar 内部代码编译后以二进制中间码形式执行,何种方案更容易发现安全问题?

@sulingjiang
Copy link

风险何在?如果我要投毒,随意往一个 JAR 里面塞点东西不是更好?何必一定要走启动前执行的命令呢?

我觉得这可以降低实施攻击的难度,脚本代码不难学

@LJS08
Copy link

LJS08 commented Aug 13, 2024

我认为 可以强制让携带有 预启动指令 的整合包带有签名,这样可以防止整合包在传递途中预启动指令被更改
(不执行没有签名的整合包的预启动指令)

@LJS08
Copy link

LJS08 commented Aug 13, 2024

可以让启动器兼容一种新的脚本语言,这种脚本语言调用启动器本身的功能来进行操作。
让整合包里带有该脚本,通过启动器来操作系统资源。
启动器或用户可以自主控制权限,以获得更大的自主权

@allMagicNB
Copy link

可以让启动器兼容一种新的脚本语言,这种脚本语言调用启动器本身的功能来进行操作。
让整合包里带有该脚本,通过启动器来操作系统资源。
启动器或用户可以自主控制权限,以获得更大的自主权

你是否在寻找:汇编语言?

@zyxkad
Copy link

zyxkad commented Aug 13, 2024

JVM 又不是沙箱,Jar 内部也可以执行命令,关键包/关键函数又从何谈起?

你说对了,执行指令的函数正式关键函数,需要严格监控的。

启动命令直接以文本形式写入整合包配置,而 Jar 内部代码编译后以二进制中间码形式执行,何种方案更容易发现安全问题?

对于分析器来说,结构化的二进制比文本歧义更少,更容易理解。

@zyxkad
Copy link

zyxkad commented Aug 13, 2024

可以让启动器兼容一种新的脚本语言,这种脚本语言调用启动器本身的功能来进行操作。 让整合包里带有该脚本,通过启动器来操作系统资源。 启动器或用户可以自主控制权限,以获得更大的自主权

不需要新的脚本语言。现有脚本语言(例如JS、Lua等)的大部分VM实现本身就在沙箱中运行。

@burningtnt
Copy link

为 Pre-Launch Command 指定沙箱毫无意义。我往你的 JAR 里投点毒,你发现不了

@zyxkad
Copy link

zyxkad commented Aug 13, 2024

当前环境不支持所使用的指令

这个问题很有趣。 TeaCon 2023 所使用的 Packwiz 是基于 Kotlin 编写并以 JVM 作为编译目标的。Packwiz-Installer 利用了 MultiMC 的 Pre-Launch Command 执行时注入的 INST_JAVA 环境变量以获取「当前游戏启动时所用的 Java 程序的绝对路径」来运行 Packwiz-Installer-Bootstrap。由此,Packwiz 利用了 JVM 本身即跨平台的特性避免了「针对不同操作系统进行特殊处理」的问题。

不妨允许根据当前操作系统、CPU 架构等的不同来决定该执行哪一个命令。就像这样:

{
  "pre-launch-command": {
    "windows-amd64": "paint.exe",
    "macos-arm64": "say hello from macOS",
    "linux-loongarch": "uname -a"
  }
}

除了操作系统和CPU架构以外,各版本shell的语法也不尽相同,并且运行环境还不一定有所需指令。

我认为 @LJS08 提议的使用单一脚本语言的方式比起 shell 来说更好。但问题是启动器作者需要进行大量工作才能支持。
@ustc-zzzz上面 说到的执行整合包 Jar 或者 class 文件我认为很不错。

@zyxkad
Copy link

zyxkad commented Aug 13, 2024

为 Pre-Launch Command 指定沙箱毫无意义。我往你的 JAR 里投点毒,你发现不了

这属于病毒查杀器的问题了。对于反病毒程序而言,jar使用的更广泛,故此其会对jar进行特殊分析。但它并不能理解自定义协议中的指令

@LJS08
Copy link

LJS08 commented Aug 13, 2024

你是否在寻找:汇编语言?

是启动器能够一定程度上限制整合包,不是整合包shellcode...

@LJS08
Copy link

LJS08 commented Aug 13, 2024

不需要新的脚本语言。现有脚本语言(例如JS、Lua等)的大部分VM实现本身就在沙箱中运行。

其实我只是想让启动器本身解释语句
这个语言可以没有变量,声明之类的东西
只需要基本的逻辑判断就足够了,启动器提供一些常量和函数。让脚本可以进行调用和简单的判断。
本质上是对启动器进行编程(什么可编程启动器)
我觉得汇编语言的形式就很适合
(简单,易于实现)

启动器直接读入脚本源代码,然后解释并执行

extraconst arch
extraconst status_code
extra end_fuction
x86_64:
    [一些操作]
    JMP End

CMP CPU_ARCH "x86_64"
JE x86_64

End:

    CALL end_fuction(SUCCESS_CODE)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants