Windows 11 用户启动项在登录前启动的现象

我给 maa 设置了自启动,之前就观测到在我输完密码进入桌面时 maa 似乎就已经 link start 了,一直怀疑 windows 的启动项在用户没有登录的情况下偷偷运行,直到昨天,我光开机没输密码,过了一段时间后进入桌面时看到 maa 已经在换基建了,再次实验,发现甚至可以在没有登录的情况下完成挂机乃至自动关机的全流程,还可以通过 maa 的远程监控实时截图,非常的奇妙!遂对 windows 的用户启动项机制进行了一番研究

首先对 maa 的自启动机制进行排查,

1
2
3
private const string CurrentUserRunKey = @"Software\Microsoft\Windows\CurrentVersion\Run";
...
key.SetValue(_registryKeyName, "\"" + _fileValue + "\"");

通过源代码可以看到采取的是通过修改注册表实现的自启动,为了确保万无一失,我还翻阅了这个文件的 git 历史记录,排查了服务项和计划任务还有 startup 文件夹,确定 maa 只使用这一种方法,即注册了一个当前用户的启动项,按理说不应该出现在用户登录前运行的现象(在此感谢 lgc 同学帮助我复现了这个问题)

那么会不会是一个通用的问题而不只是针对 maa 呢,我让 ai 帮助我生成了一个 python 脚本(原谅我硬编码日志路径,也没有做清理工作 😇 )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import os
import sys
import winreg
from datetime import datetime

def add_to_startup():
reg_name = "MyPythonAutoStart"
reg_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
target_value = f'"{os.path.abspath(sys.argv[0])}"'
print(f" 尝试将脚本添加到注册表自启项 : {target_value}")
try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, reg_path, 0, winreg.KEY_ALL_ACCESS)
try:
current_value, _ = winreg.QueryValueEx(key, reg_name)
if current_value == target_value:
# 已经设置,无需重复
print(" 注册表项已存在,无需重复设置 ")
winreg.CloseKey(key)
return
except FileNotFoundError:
pass # 没有该项,继续设置
winreg.SetValueEx(key, reg_name, 0, winreg.REG_SZ, target_value)
winreg.CloseKey(key)
print(" 成功添加到注册表自启项 ")
except Exception as e:
print(f" 设置注册表失败 : {e}")

def write_log():
# 使用 D 盘根目录作为日志路径
log_path = r"D:\startup.log"

try:
with open(log_path, "a", encoding="utf-8") as f:
f.write(f"[{datetime.now()}] Python 自启脚本已启动 \n")
print(f" 日志已写入 : {log_path}")
except Exception as e:
print(f" 写入日志失败 : {e}")

if __name__ == "__main__":
add_to_startup()
write_log()
input()

然后我将这个 python 脚本用 pyinstaller 打包成 exe, 按照与 maa 相同的原理注册了一个用户启动项,将输入密码进入系统的时间与脚本日志中记录的时间进行比对,发现产生了与 maa 相同的现象,用户启动项在用户登录之前就已经在运行了!

紧接着我创建了一个新用户,来检测这个问题是否会影响到多用户体验,将添加了 python 脚本启动项(简称为启动项)的用户称为 admin,将我新添加的用户称为 guest,至于为什么考虑到了上一次登录的是哪一位用户,为什么有后台用户,就是不小心发现的啦

上一次登录用户 这一次登录用户 输入密码时间是否早于启动项启动时间 后台有无另外一个用户在运行
admin admin
admin guest
guest admin
guest guest 没有启动

是的,你没有看错,在特定情况下,我可以让一个用户的程序在另外一个用户没有登录的时候就进行启动,甚至可以实现登录 admin 后 maa 在 guest 用户底下挂机,然后给电脑自动关机!我们还可以引出一个大胆的猜测, windows 会通过某种手段“缓存”上一次登录用户的一些东西,在紧接着的下一次启动时会把上一次登录用户的用户启动项偷偷启动,达到一种加快启动速度的目的,哪怕你还没有登录,你的用户启动项已经启动咯 😋👍 ,在登录进去后,如果两次登录的用户不同,还可以在任务管理器观察到另外一个用户在运行 😭😆

那么这种机制究竟是为什么呢,我在网上进行搜索和询问 ai 都没有得到沾边的答复,不过 ai 说可能是因为 windows 的混合启动机制,但是我也找不到对这个混合启动进行开关的地方,也没有找到相关的休眠文件,因为这个机制也不会针对用户启动项啊 😇

不过歪打正着,我发现使用 shutdown \s \t 0 命令进行关机可以完全消除用户启动项先于登录启动以及奇怪的第二个用户在后台的情况,与我的猜测也没有冲突(翻看了 maa 的代码,发现 maa 的自动关机也是使用的这个命令,所以之前偶尔才能观察到!),也许是这条命令会导致冷启动的原因??

这到底是 feature 还是 bug,我也不好说,只开机密码都不用输就可以挂机,简直是懒人福音,但是,但是,我觉得这个会存在一定的安全隐患,像这样通过注册表添加用户启动项是完全不需要管理员权限的,在没有登录前就运行,是不是有点过分了(能否在 widnows 里运行一个安卓虚拟机,通过 adb 就可以拥有一个云手机 / 黑客在你没有登录的情况下在你的电脑上执行命令 😱 ),而且在后台多塞一个用户,并且还能运行另外一个用户的自启动程序,也严重不符合常识吧 😡