winbox-sandbox 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. winbox_sandbox-1.0.2/LICENSE +61 -0
  2. winbox_sandbox-1.0.2/MANIFEST.in +44 -0
  3. winbox_sandbox-1.0.2/PKG-INFO +458 -0
  4. winbox_sandbox-1.0.2/README.md +438 -0
  5. winbox_sandbox-1.0.2/RELEASE_NOTES.md +182 -0
  6. winbox_sandbox-1.0.2/Test/ac_env_probe.c +210 -0
  7. winbox_sandbox-1.0.2/Test/boom_probe.c +27 -0
  8. winbox_sandbox-1.0.2/Test/build_ac_env_probe.ps1 +46 -0
  9. winbox_sandbox-1.0.2/Test/build_boom_probe.ps1 +42 -0
  10. winbox_sandbox-1.0.2/Test/build_il_probe.ps1 +32 -0
  11. winbox_sandbox-1.0.2/Test/il_probe.c +56 -0
  12. winbox_sandbox-1.0.2/Test/test_all.py +9676 -0
  13. winbox_sandbox-1.0.2/broker/winboxbroker.c +1079 -0
  14. winbox_sandbox-1.0.2/examples/01_quickstart.py +23 -0
  15. winbox_sandbox-1.0.2/examples/02_tiers.py +24 -0
  16. winbox_sandbox-1.0.2/examples/03_manager_preflight.py +25 -0
  17. winbox_sandbox-1.0.2/examples/04_files.py +25 -0
  18. winbox_sandbox-1.0.2/examples/05_browser.py +29 -0
  19. winbox_sandbox-1.0.2/examples/README.md +25 -0
  20. winbox_sandbox-1.0.2/kernel/winboxfake/BUILD.md +108 -0
  21. winbox_sandbox-1.0.2/kernel/winboxfake/fake_dll_probe.c +51 -0
  22. winbox_sandbox-1.0.2/kernel/winboxfake/late_dll_probe.c +36 -0
  23. winbox_sandbox-1.0.2/kernel/winboxfake/late_host.c +36 -0
  24. winbox_sandbox-1.0.2/kernel/winboxfake/winboxfake.c +1065 -0
  25. winbox_sandbox-1.0.2/kernel/winboxflt/BUILD.md +184 -0
  26. winbox_sandbox-1.0.2/kernel/winboxflt/comm.c +687 -0
  27. winbox_sandbox-1.0.2/kernel/winboxflt/enummerge.c +970 -0
  28. winbox_sandbox-1.0.2/kernel/winboxflt/ipcvirt.c +194 -0
  29. winbox_sandbox-1.0.2/kernel/winboxflt/pathvirt.c +733 -0
  30. winbox_sandbox-1.0.2/kernel/winboxflt/process.c +36 -0
  31. winbox_sandbox-1.0.2/kernel/winboxflt/regvirt.c +386 -0
  32. winbox_sandbox-1.0.2/kernel/winboxflt/winboxflt.c +680 -0
  33. winbox_sandbox-1.0.2/kernel/winboxflt/winboxflt.h +648 -0
  34. winbox_sandbox-1.0.2/kernel/winboxflt/winboxflt.inf +44 -0
  35. winbox_sandbox-1.0.2/main.py +62 -0
  36. winbox_sandbox-1.0.2/pyproject.toml +78 -0
  37. winbox_sandbox-1.0.2/setup.cfg +4 -0
  38. winbox_sandbox-1.0.2/winbox/Test/ac_env_probe.c +210 -0
  39. winbox_sandbox-1.0.2/winbox/Test/bin/ac_env_probe.exe +0 -0
  40. winbox_sandbox-1.0.2/winbox/Test/bin/boom_probe.exe +0 -0
  41. winbox_sandbox-1.0.2/winbox/Test/bin/il_probe.exe +0 -0
  42. winbox_sandbox-1.0.2/winbox/Test/boom_probe.c +27 -0
  43. winbox_sandbox-1.0.2/winbox/Test/build_ac_env_probe.ps1 +46 -0
  44. winbox_sandbox-1.0.2/winbox/Test/build_boom_probe.ps1 +42 -0
  45. winbox_sandbox-1.0.2/winbox/Test/build_il_probe.ps1 +32 -0
  46. winbox_sandbox-1.0.2/winbox/Test/il_probe.c +56 -0
  47. winbox_sandbox-1.0.2/winbox/__init__.py +152 -0
  48. winbox_sandbox-1.0.2/winbox/__main__.py +5 -0
  49. winbox_sandbox-1.0.2/winbox/api.py +1383 -0
  50. winbox_sandbox-1.0.2/winbox/bin/dokan2.dll +0 -0
  51. winbox_sandbox-1.0.2/winbox/bin/dokanctl.exe +0 -0
  52. winbox_sandbox-1.0.2/winbox/bin/mirror.exe +0 -0
  53. winbox_sandbox-1.0.2/winbox/bin/winboxbroker.exe +0 -0
  54. winbox_sandbox-1.0.2/winbox/bin/winboxfake.dll +0 -0
  55. winbox_sandbox-1.0.2/winbox/broker/bin/winboxbroker.exe +0 -0
  56. winbox_sandbox-1.0.2/winbox/broker/build_broker.ps1 +35 -0
  57. winbox_sandbox-1.0.2/winbox/broker/winboxbroker.c +1079 -0
  58. winbox_sandbox-1.0.2/winbox/capabilities.py +84 -0
  59. winbox_sandbox-1.0.2/winbox/certs/winbox-test-signing.cer +0 -0
  60. winbox_sandbox-1.0.2/winbox/cli.py +399 -0
  61. winbox_sandbox-1.0.2/winbox/config.py +388 -0
  62. winbox_sandbox-1.0.2/winbox/deploy.py +1112 -0
  63. winbox_sandbox-1.0.2/winbox/dokany/Dokan_x64.msi +0 -0
  64. winbox_sandbox-1.0.2/winbox/drivers/winboxflt.sys +0 -0
  65. winbox_sandbox-1.0.2/winbox/errors.py +6 -0
  66. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/BUILD.md +108 -0
  67. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/fake_dll_probe.c +51 -0
  68. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/late_dll_probe.c +36 -0
  69. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/late_dll_probe.dll +0 -0
  70. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/late_host.c +36 -0
  71. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/winboxfake.c +1065 -0
  72. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/winboxfake.dll +0 -0
  73. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/winboxfake_latehost.exe +0 -0
  74. winbox_sandbox-1.0.2/winbox/kernel/winboxfake/winboxfake_probe.exe +0 -0
  75. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/BUILD.md +184 -0
  76. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/comm.c +687 -0
  77. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/enummerge.c +970 -0
  78. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/ipcvirt.c +194 -0
  79. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/pathvirt.c +733 -0
  80. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/process.c +36 -0
  81. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/regvirt.c +386 -0
  82. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/winboxflt.c +680 -0
  83. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/winboxflt.h +648 -0
  84. winbox_sandbox-1.0.2/winbox/kernel/winboxflt/winboxflt.inf +44 -0
  85. winbox_sandbox-1.0.2/winbox/main.py +62 -0
  86. winbox_sandbox-1.0.2/winbox/manager.py +736 -0
  87. winbox_sandbox-1.0.2/winbox/native/__init__.py +3 -0
  88. winbox_sandbox-1.0.2/winbox/native/api.py +533 -0
  89. winbox_sandbox-1.0.2/winbox/native/broker.py +585 -0
  90. winbox_sandbox-1.0.2/winbox/native/desktop.py +276 -0
  91. winbox_sandbox-1.0.2/winbox/native/dokan_bootstrap.py +179 -0
  92. winbox_sandbox-1.0.2/winbox/native/dokan_mirror.py +598 -0
  93. winbox_sandbox-1.0.2/winbox/native/dokany.py +441 -0
  94. winbox_sandbox-1.0.2/winbox/native/egress.py +409 -0
  95. winbox_sandbox-1.0.2/winbox/native/elevation.py +146 -0
  96. winbox_sandbox-1.0.2/winbox/native/errors.py +63 -0
  97. winbox_sandbox-1.0.2/winbox/native/fakedll.py +155 -0
  98. winbox_sandbox-1.0.2/winbox/native/fsutil.py +109 -0
  99. winbox_sandbox-1.0.2/winbox/native/inject.py +109 -0
  100. winbox_sandbox-1.0.2/winbox/native/job.py +271 -0
  101. winbox_sandbox-1.0.2/winbox/native/kernelflt.py +669 -0
  102. winbox_sandbox-1.0.2/winbox/native/launcher.py +567 -0
  103. winbox_sandbox-1.0.2/winbox/native/pipeprobe.py +290 -0
  104. winbox_sandbox-1.0.2/winbox/native/process.py +457 -0
  105. winbox_sandbox-1.0.2/winbox/native/registry.py +80 -0
  106. winbox_sandbox-1.0.2/winbox/native/resources.py +484 -0
  107. winbox_sandbox-1.0.2/winbox/native/tokens.py +578 -0
  108. winbox_sandbox-1.0.2/winbox/native/user_boundary.py +1034 -0
  109. winbox_sandbox-1.0.2/winbox/native/vfs.py +365 -0
  110. winbox_sandbox-1.0.2/winbox/native/virt_model.py +242 -0
  111. winbox_sandbox-1.0.2/winbox/osdetect.py +282 -0
  112. winbox_sandbox-1.0.2/winbox/pyproject.toml +78 -0
  113. winbox_sandbox-1.0.2/winbox/sandbox.py +976 -0
  114. winbox_sandbox-1.0.2/winbox/state.py +197 -0
  115. winbox_sandbox-1.0.2/winbox.cmd +26 -0
  116. winbox_sandbox-1.0.2/winbox_sandbox.egg-info/PKG-INFO +458 -0
  117. winbox_sandbox-1.0.2/winbox_sandbox.egg-info/SOURCES.txt +119 -0
  118. winbox_sandbox-1.0.2/winbox_sandbox.egg-info/dependency_links.txt +1 -0
  119. winbox_sandbox-1.0.2/winbox_sandbox.egg-info/entry_points.txt +2 -0
  120. winbox_sandbox-1.0.2/winbox_sandbox.egg-info/top_level.txt +1 -0
@@ -0,0 +1,61 @@
1
+ winbox 专有许可协议(Proprietary License)
2
+ 版权所有 (c) 2026 winbox 版权持有人。保留所有权利。
3
+
4
+ 1. 授权范围(默认不授予任何使用权)
5
+
6
+ 本软件(含源代码、二进制文件、驱动、文档、示例与随包载荷,以下统称"本软件")**默认不授予任何
7
+ 使用权**。无论**商业用途**还是**个人用途**,任何形式的使用都必须**事先取得版权持有人的书面授权**。
8
+
9
+ 2. 未经授权即禁止的行为(包括但不限于)
10
+
11
+ a. 复制、下载后使用、安装、部署、运行本软件或其任何部分;
12
+ b. 修改、翻译、演绎、反编译(法律强制允许的情形除外)、拆分或制作衍生作品;
13
+ c. 分发、公开传播、出租、出借、转售、再许可、以托管服务(SaaS)形式提供,或以任何方式使第三方获得;
14
+ d. 移除、遮盖或规避本软件中的版权声明、许可条款或技术保护措施;
15
+ e. 用于商业产品、商业服务或内部生产经营活动,或以本软件提供有偿服务;
16
+ f. 将本软件或其衍生作品作为自己的产品发布或据以申请知识产权。
17
+
18
+ 3. 取得授权
19
+
20
+ 任何形式的使用(含个人用途与商业用途)均需事先获得书面授权。授权申请与商务事宜请联系版权持有人:
21
+
22
+ 联系方式:<请在此填写版权持有人的联系方式>
23
+
24
+ 经授权的使用必须严格限定在授权范围(用途、期限、地域、数量)之内。
25
+
26
+ 4. 第三方组件
27
+
28
+ 本软件随包分发的第三方组件(例如 Dokan 运行时/驱动、Windows SDK 相关头文件等)适用其各自的
29
+ 许可条款;本协议不改变这些条款,使用者必须同时遵守。随包自签证书与自研 minifilter、broker、
30
+ 伪造层等同样属于本软件,受本协议约束。
31
+
32
+ 5. 免责声明
33
+
34
+ 本软件按"现状(AS IS)"提供,不附带任何明示或默示的担保,包括但不限于适销性、特定用途适用性、
35
+ 所有权与不侵权担保。在任何情况下,版权持有人均不对因本软件或其使用而产生的任何索赔、损害或
36
+ 其他责任负责,无论是在合同诉讼、侵权行为还是其它方面,即使已被告知可能发生此类损害。
37
+
38
+ 6. 终止
39
+
40
+ 违反本协议任何条款,已授予的授权(如有)自动终止;使用者必须立即停止使用并销毁本软件的全部副本。
41
+
42
+ 7. 适用法律与争议解决
43
+
44
+ 本协议适用版权持有人主要营业地法律;因本协议产生的争议提交该地有管辖权的法院解决。
45
+
46
+ --------------------------------------------------------------------------------
47
+ English summary (for reference only; the Chinese text above prevails)
48
+
49
+ Proprietary software. Copyright (c) 2026 the winbox copyright holder. All rights reserved.
50
+
51
+ NO LICENSE IS GRANTED BY DEFAULT. ANY use - whether commercial OR personal - requires prior
52
+ written authorization from the copyright holder. Without such authorization you may not copy,
53
+ install, deploy, run, modify, translate, reverse engineer (except where mandatory law permits),
54
+ distribute, sublicense, rent, sell, host as a service, or otherwise make this software or any
55
+ part of it available to any third party, nor remove any copyright or license notice.
56
+
57
+ Bundled third-party components remain under their own licenses, which must also be observed.
58
+
59
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT
60
+ SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM, OUT
61
+ OF OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
@@ -0,0 +1,44 @@
1
+ # Source distribution contents.
2
+ #
3
+ # The wheel is the supported install path (pip install winbox-sandbox /
4
+ # uv add winbox-sandbox) and is self-contained: every runtime payload
5
+ # (DLL, broker, Dokan MSI, signed minifilter, certificate) travels inside
6
+ # winbox/bin, winbox/dokany, winbox/drivers and winbox/certs.
7
+ #
8
+ # The sdist additionally carries the material needed to verify the package:
9
+ # the single-file self-test suite, the examples, and the driver/service sources.
10
+
11
+ include LICENSE
12
+ include README.md
13
+ include RELEASE_NOTES.md
14
+ include main.py
15
+ include winbox.cmd
16
+
17
+ # Runtime payloads (also declared in [tool.setuptools.package-data]).
18
+ recursive-include winbox/bin *.dll *.exe
19
+ recursive-include winbox/dokany *.msi
20
+ recursive-include winbox/drivers *.sys
21
+ recursive-include winbox/certs *.cer
22
+
23
+ # Verification material: self-test suite + native probe sources and build scripts.
24
+ # Compiled probe binaries (Test/bin/) are deliberately excluded - they are build output.
25
+ include Test/test_all.py
26
+ include Test/*.c
27
+ include Test/*.ps1
28
+
29
+ # Tutorials.
30
+ recursive-include examples *.py *.md
31
+
32
+ # Sources of the shipped binaries (transparency / provenance).
33
+ recursive-include kernel *.c *.h *.inf *.md
34
+ recursive-include broker *.c
35
+
36
+ # Never ship build/test residue.
37
+ global-exclude *.py[cod] *.obj *.pdb *.log
38
+ prune build
39
+ prune dist
40
+ prune .winbox_env
41
+ prune Test/.winbox_env
42
+ prune Test/bin
43
+ prune .venv
44
+ prune __pycache__
@@ -0,0 +1,458 @@
1
+ Metadata-Version: 2.4
2
+ Name: winbox-sandbox
3
+ Version: 1.0.2
4
+ Summary: Windows 10/11 application sandbox: Job Object + fake C tree + Dokan drive + dedicated-account boundary + in-process API view faking + local egress controller + self-written minifilter, with automatic backend selection, portable deployment and a single SandboxManager facade. Pure standard library.
5
+ Author: winbox
6
+ License: Proprietary. Any use, commercial or personal, requires prior written authorization from the copyright holder. See LICENSE.
7
+ Keywords: sandbox,appcontainer,windows,security,isolation,minifilter
8
+ Classifier: Operating System :: Microsoft :: Windows
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: License :: Other/Proprietary License
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Topic :: System :: Systems Administration
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # winbox —— Windows 10/11 轻量应用沙箱(可运行/安装任意 exe,含浏览器)
22
+
23
+ `winbox` 把"不受信任的程序"关进一个由**多层独立机制**叠加出来的盒子里,只用一个 Python 包交付:
24
+ 纯标准库运行、自签驱动随包、一条命令完成部署、启动前必给**环境检测报告**。
25
+
26
+ ```python
27
+ from winbox import SandboxManager
28
+
29
+ mgr = SandboxManager() # 只探测本机,不改任何设置
30
+ with mgr.session("demo") as sb: # 启动前自动打印环境检测报告
31
+ r = sb.run(["cmd.exe", "/c", "echo hi"], timeout=10)
32
+ print(r.ok, r.exit_code, (r.stdout or "").strip())
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 1. 安装
38
+
39
+ **环境要求**:Windows 10/11 **x64** + **64 位 Python ≥ 3.11**。全部运行时依赖都是 Python 标准库
40
+ (`ctypes` / `winreg` / `subprocess` / `tomllib` …),**不引入任何第三方包**。
41
+
42
+ 发行名是 `winbox-sandbox`,导入名是 `winbox`(PyPI 上 `winbox` 这个名字属于另一个无关项目)。
43
+
44
+ ```powershell
45
+ pip install winbox-sandbox # pip
46
+ uv add winbox-sandbox # uv(项目)
47
+ uv tool install winbox-sandbox # uv(全局命令)
48
+ ```
49
+
50
+ 装完自检:
51
+
52
+ ```powershell
53
+ python -c "import winbox; print(winbox.__version__, winbox.detect_os().display_name)"
54
+ winbox info # 环境 + 后端可用性(只读,从不提权)
55
+ ```
56
+
57
+ > 只支持 Windows。在别的平台上 `import winbox` 会立刻给出明确报错,不会拖到运行期才失败。
58
+
59
+ ### 1.1 部署(一次管理员权限)
60
+
61
+ 安装包只是把文件放到磁盘上;**沙箱组件需要一次提权部署**:
62
+
63
+ ```powershell
64
+ python -m winbox.deploy install # 一次管理员权限(UAC):把所需组件一次装齐
65
+ winbox deploy check # 部署真相(只读,不提权)
66
+ winbox deploy plan # 只看计划,不动手
67
+ ```
68
+
69
+ `install` 的步骤(每步**先探测再动手**,重复执行不会重复安装):
70
+
71
+ ```
72
+ preflight → layout → dokan → api_fake → account → credential → driver → trust → broker → manifest
73
+ ```
74
+
75
+ * `dokan` — 包内 MSI,装 Dokan 运行时(虚拟盘层);
76
+ * `api_fake` — 包内 `winboxfake.dll`;
77
+ * `account` / `credential` — 专用账户 + 凭据 + deny-ACE 封印;
78
+ * `driver` — 注册/启动 `winboxflt`(仅当有已签名镜像,包内自带);
79
+ * `trust` — 让内核镜像**可加载**:导入**包内证书**(与包内驱动镜像的签名者一致)并按需开 test-signing;
80
+ **test-signing 需要重启生效**,所以只报 `needs_reboot: true`,**不替你重启**;
81
+ * `broker` — 安装并启动 `winboxbroker`(已在跑且管道应答 ⇒ 记为 `skipped`)。
82
+
83
+ 退出开关:`--no-dokan` / `--no-kernel` / `--no-trust` / `--no-broker`。
84
+
85
+ > **路径 A(自签)是默认路径**:不需要购买任何证书。代价是必须关掉 Secure Boot 并接受一次 test-signing;
86
+ > 若受管机器不允许关 Secure Boot,则只能走"EV 证书 + Microsoft attestation"的零操作路径。
87
+
88
+ ### 1.2 两类落盘位置(都可重定向)
89
+
90
+ | 位置 | 默认值 | 内容 |
91
+ | --- | --- | --- |
92
+ | **安装根** | `%ProgramData%\winbox\` | 驱动 / broker / Dokan 工具 / 证书 |
93
+ | **沙箱根(store root)** | 源码树内为 `<项目目录>\.winbox_env\`;安装成包后为 `%LOCALAPPDATA%\winbox\stores\` | 每个沙箱一份伪造 `C:\` 骨架、档案、overlay、日志 |
94
+
95
+ 沙箱根可整目录删除,下次运行自动重建。解析优先级:
96
+ **显式 `root_dir` 参数 > 配置项 `root_dir` > 环境变量 `WINBOX_ROOT` > 上面的默认值**。
97
+ 想把它放到数据盘或临时目录:
98
+
99
+ ```powershell
100
+ $env:WINBOX_ROOT = 'D:\winbox-stores' # 本次会话的所有沙箱都落到 D 盘
101
+ winbox info # 报告里的 root= 会如实反映实际位置
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 2. 它是怎么工作的
107
+
108
+ | 层 | 机制 | 作用 |
109
+ |---|---|---|
110
+ | **L0 资源/生命周期** | Job Object | 内存/CPU/进程数限制,退出时**整棵进程树**终止 |
111
+ | **L1 伪造文件系统** | 每个沙箱一份 store(伪造 Windows 骨架 + 环境重定向) | 程序以为在读写 `C:\`,实际落在 store 内 |
112
+ | **L1 虚拟盘 `S:`** | Dokan 把 store 挂成真实盘符 | 需要真实盘符的程序也能跑 |
113
+ | **L1 API 视图伪装** | `winboxfake.dll` 挂起态注入,改写各模块导入表 | 进程内看到的盘符/已知文件夹被改写,后加载的 DLL 同样覆盖 |
114
+ | **L1′ AppContainer 低完整性盒子** | `NtCreateLowBoxToken` 派生真 lowbox 令牌 + 包 SID 授权**仅 store** | 宿主目录默认**拒写**(连用户 `%TEMP%` 也拒),同用户宿主进程**不可杀** |
115
+ | **L2 账户边界** | 专用账户(默认 `winbox_sbx`) | 免提权闭合"选择器只见宿主盘 / 下载逃逸 / 硬编码写宿主" |
116
+ | **L3 内核硬界** | 自研 minifilter `winboxflt`(随包已签名) | 默认全闭 + 读白名单 + 盒外写**拒绝**(fail-closed) |
117
+ | **可选:特权 broker** | `winboxbroker` LocalSystem 服务 + 严格 ACL 命名管道 | 免提权起 Medium 进程(Chromium broker 模型);opt-in |
118
+ | **可选:网络出口控制** | 本地代理 + 动态断网/过滤 | `network=none/localhost/outbound/...` |
119
+
120
+ **分级(tier)**:`appcontainer` > `restricted` > `jobonly`;`auto` 是策略不是档位 —— 它按这个顺序选本机**实际可用**的最强档,
121
+ 启动前报告里的 `tier: auto -> X` 才是这次真正会用的一档。
122
+
123
+ ---
124
+
125
+ ## 3. 快速开始
126
+
127
+ ### 3.1 Python
128
+
129
+ ```python
130
+ import winbox
131
+
132
+ # 一次性运行(用完即收)
133
+ r = winbox.run_once(["cmd.exe", "/c", "ver"], tier="auto", timeout=15)
134
+ print(r.ok, r.exit_code, r.stdout)
135
+
136
+ # 会话式:多次运行、共享 store 与档案
137
+ with winbox.session("work", tier="appcontainer", cleanup_on_exit=True) as sb:
138
+ sb.run(["cmd.exe", "/c", "echo a"], timeout=10)
139
+ sb.run(["cmd.exe", "/c", "dir S:\\"], timeout=10)
140
+ print(sb.status()) # 含 backend / store_dir / api_fake 等真实状态
141
+ ```
142
+
143
+ ### 3.2 单类入口(推荐)
144
+
145
+ ```python
146
+ from winbox import SandboxManager
147
+
148
+ mgr = SandboxManager()
149
+ print(mgr.summary()) # 版本 / root / 各档是否可用 + 原因 / 驱动 / broker
150
+ print(mgr.component_gaps()) # 还缺哪些组件(健康机为空列表)
151
+ mgr.install() # 需要管理员:装配全部组件
152
+ with mgr.session("demo", cleanup_on_exit=True) as sb:
153
+ print(sb.run(["cmd.exe", "/c", "echo hi"], timeout=10).exit_code)
154
+ print(sb.resources()["memory"]["peak_job_bytes"]) # 该沙箱峰值内存(整棵进程树)
155
+ print(mgr.verify(live=True).summary()) # 本机验收报告(每项都实测,ok=None 表示测不到)
156
+ ```
157
+
158
+ ### 3.3 命令行
159
+
160
+ ```powershell
161
+ winbox info # 环境 + 后端可用性(只读,从不提权)
162
+ winbox run cmd.exe --wait --args /c echo hello # 跑一条命令
163
+ winbox run --low cmd.exe --wait --args /c dir # 以 Low 完整性跑
164
+ winbox status demo # 某个沙箱的状态
165
+ winbox list | prune # 列出 / 清理沙箱
166
+ winbox deploy check # 部署真相(只读)
167
+ winbox deploy install # 管理员:一次装齐
168
+ winbox broker status # broker 服务/镜像/管道真相
169
+ winbox selftest # 本机功能自检
170
+ ```
171
+
172
+ `python -m winbox …` 与 `winbox …` 等价;源码树里的 `winbox.cmd` 是 Windows 便捷入口,
173
+ `python main.py …` 是可直接运行的顶层入口(不带参数时打印环境适配报告)。
174
+
175
+ ### 3.4 本机功能自检
176
+
177
+ ```powershell
178
+ python Test\test_all.py # 源码树内:全量(非提权;需管理员的用例记为 SKIP)
179
+ python Test\test_all.py --quick # 跳过耗时的压力/泄漏用例
180
+ winbox selftest # 经 CLI 调用(会先请求一次管理员权限)
181
+ ```
182
+
183
+ 自检逐项实测本机能力:主机真值、配置、网络能力、令牌与 Job Object、伪造 `C:` 树与 minifilter 决策表、
184
+ 三档后端、公开 API、健壮性/路径模糊、**并行沙箱**、**资源占用统计**、Dokan、账户边界、出口控制、
185
+ 内核契约、broker、部署、提权策略、门面、浏览器与压力;每项要么给出可观测事实的断言,
186
+ 要么带**具体原因**记为 `SKIP`(测不到绝不记为通过)。
187
+
188
+ > 自测套件属于**源码树**的一部分,不随 wheel 分发;只有源码树里(或从 sdist 解包后)
189
+ > 才能跑它,发行包里 `winbox selftest` 会如实打印这一行提示而不是假装跑过。
190
+
191
+ ---
192
+
193
+ ## 4. 启动前必有环境检测报告
194
+
195
+ **每一次 `session()` / `run_once()` / `start()` 都先做只读探测,再把报告打到 stdout**,然后才启动:
196
+
197
+ ```
198
+ ----------- winbox preflight (before start) -----------
199
+ winbox : 1.0.2 | python 3.12.x (64-bit) | root=C:\ProgramData\winbox
200
+ host : Windows 11 (build 22631) | elevated=no
201
+ tier : auto -> appcontainer (strongest tier available on this host)
202
+ [OK] auto
203
+ [OK] appcontainer
204
+ [OK] restricted
205
+ [OK] jobonly
206
+ driver : image=test_signed ready=True running=True answering=True
207
+ broker : installed=True running=True available=True
208
+ dokan : runtime=True
209
+ blockers : none
210
+ warnings : 1
211
+ - not elevated: install / trust --apply / driver cases need one UAC prompt
212
+ -------------------------------------------------------
213
+ ```
214
+
215
+ 怎么读:
216
+
217
+ * `tier: auto -> X` 是**这次真正会用**的档位;自动兼容阶梯仍可能在单个进程上再调整(实际值看 `RunResult.backend`);
218
+ * `blockers` 非空 = 按当前配置**这次启动不该被信任**(例如显式要的档位在本机不可用、配置要求内核层但 minifilter 不应答);
219
+ * `warnings` = "能跑,但你必须知道"(未提权、驱动镜像未就绪、broker 不可用、appcontainer 不可用、Python 低于声明下限……);
220
+ * 报告只写**探测到的事实**;测不到的项一律 `SKIP/UNKNOWN` 并写明原因,**绝不写成通过**。
221
+
222
+ 控制与取数:
223
+
224
+ | 想要 | 写法 |
225
+ |---|---|
226
+ | 只要数据不打印 | `mgr.preflight_report(tier="restricted")` → dict(`report`/`blockers`/`warnings`/`tier`/`tiers`/`driver`/`broker`/`environment`/`signing`) |
227
+ | 单次静音 | `mgr.session("demo", report=False)` |
228
+ | 整体静音(热循环) | `SandboxManager(preflight=False)` |
229
+ | 有 blocker 直接抛错 | `mgr.preflight(strict=True)` → `SandboxError` |
230
+ | 强制重新探测 | `mgr.preflight_report(force=True)` |
231
+ | 缓存时长 | `SandboxManager(preflight_ttl=60.0)`(秒) |
232
+ | 缺件就自动补齐 | `mgr.ensure_environment()`(默认跟随构造时的 `ensure=True`) |
233
+
234
+ **初始化自足**:每次启动前除了打印报告,还会逐个只读探测必需组件(Dokan / minifilter / 内核信任 / broker),
235
+ **缺什么装什么**;全都在就 `skipped` 并写明检测到什么。缺件且**没有管理员权限**时,返回 `needs_elevation`
236
+ 并把**那一条命令**打印出来 —— **绝不静默降级**。
237
+
238
+ ---
239
+
240
+ ## 5. 提权:三层入口都能设置
241
+
242
+ | 入口 | 不提权 | 提权 |
243
+ |---|---|---|
244
+ | **CLI 全局** | `--no-elevate`(任意位置;提权门控的工作如实报 SKIP) | `selftest` / `deploy install` / `deploy uninstall` / `deploy trust --apply` **自动一次 UAC**;`run --admin` 选择性提权(默认不给 `run` 提权:那会改变沙箱进程的父进程) |
245
+ | **只读命令** | `info` / `check` / `trust`(dry-run) / `list` / `status` | 从不提权,保持"在该权限下不可用"的诚实状态 |
246
+ | **Python API** | `SandboxManager(elevation="never")`(默认):只返回 `needs_elevation` + 精确命令 | `SandboxManager(elevation="auto")`:`ensure_environment()` 会自己用一次 UAC 跑 `python -m winbox.deploy install` |
247
+ | **有界提权执行** | — | `mgr.run_elevated(argv, timeout=900)` → 在提权子进程里跑给定命令并返回退出码;已提权时就地执行,不重复弹窗 |
248
+
249
+ ```python
250
+ from winbox import SandboxManager
251
+
252
+ m = SandboxManager() # 默认 never
253
+ print(m.elevation, m.as_dict()["elevation"])
254
+ print(m.ensure_environment(install=False))
255
+ # -> {'ok': False, 'skipped': True, 'detected': 'gaps not fixed because install=False',
256
+ # 'action': 'python -m winbox.deploy install'}
257
+
258
+ a = SandboxManager(elevation="auto") # 允许自己提权补齐
259
+ print(a.ensure_environment()) # 缺件时走一次 UAC,返回 elevated_install 结果
260
+
261
+ # 显式、有界地跑一条特权命令
262
+ print(m.run_elevated(["python", "-m", "winbox.deploy", "trust", "--apply"]))
263
+ ```
264
+
265
+ 非法策略值在构造时就拒绝:`ValueError: unknown elevation policy 'bogus'; use 'never' or 'auto'`。
266
+
267
+ > 注意:`SandboxConfig.elevation_policy`(`auto`/`appcontainer`/`restricted`/`jobonly`)是**沙箱后端档位**策略,
268
+ > 与"本进程是否提权"是两件事。
269
+
270
+ ---
271
+
272
+ ## 6. 档位语义与实测边界(重要)
273
+
274
+ | 档位 | 隔离内容 | 写宿主用户目录 | 说明 |
275
+ |---|---|---|---|
276
+ | `jobonly` | 仅 Job Object(资源/生命周期) | **不阻止** | 无文件系统边界,**不要**用它做数据隔离 |
277
+ | `restricted` | 受限令牌(可 low 或 medium) | `low`:**阻止**;`medium`:**不阻止** | 浏览器等程序需要 `medium`;要数据隔离就用 `low` 或换档 |
278
+ | `appcontainer` | 真 lowbox + 包 SID 授权仅 store | **阻止**(连 `%TEMP%` 也拒) | 免提权可用,是强边界档 |
279
+ | `user_boundary`(账户边界) | 专用账户 | **阻止**(宿主目录属于另一个用户) | 免提权闭合选择器/下载/硬编码写宿主 |
280
+
281
+ **结论**:沙箱内浏览器是否需要"写不出去",取决于你选的档位;**浏览器要数据隔离请用 `appcontainer` 或账户边界**。
282
+
283
+ ---
284
+
285
+ ## 7. 浏览器(含"禁止项")
286
+
287
+ ```python
288
+ import winbox
289
+
290
+ print(winbox.BROWSER_REQUIRED_FLAGS) # 壳内跑浏览器必需的参数
291
+ argv = [r"C:\Program Files\Google\Chrome\Application\chrome.exe",
292
+ "--headless=new", "--no-sandbox", "--disable-gpu",
293
+ "--virtual-time-budget=3000", "--dump-dom", "about:blank"]
294
+ with winbox.session("browser", tier="restricted") as sb:
295
+ r = sb.run(argv, timeout=120)
296
+ print(r.exit_code, (r.stdout or "")[:80])
297
+ ```
298
+
299
+ * `--no-sandbox` / `--disable-gpu` 是**在受限令牌内让 Chromium 真正跑起来**的必要条件(否则 GPU/渲染进程起不来);
300
+ * **生产部署禁止开调试通道**:`--remote-debugging-port` / `--remote-debugging-pipe` / `--remote-allow-origins`
301
+ 会把页面能力提升到"能读宿主文件系统"(一次 `DOM.setFileInputFiles` 就能把任意宿主路径交给页面读取,
302
+ 既不需要文件对话框,也不需要用户手势)。用 `winbox.browser_arg_warnings([...])` 自检:
303
+
304
+ ```python
305
+ warns = winbox.browser_arg_warnings(["--headless=new", "--remote-debugging-port=9222"])
306
+ assert not warns, warns # 生产里必须为空
307
+ ```
308
+
309
+ ---
310
+
311
+ ## 8. API 参考
312
+
313
+ ### 8.1 `SandboxManager`(别名 `Manager`)—— 单类入口
314
+
315
+ | 分组 | 方法 |
316
+ |---|---|
317
+ | 身份/配置 | `root` `account` `tier` `config` `default_timeout` `version` `elevation` `configure()` `as_dict()` |
318
+ | 环境真相(只读) | `environment()` `doctor()` `tiers()` `check()` `summary()` `preflight()` `preflight_report()` `planned_tier()` `component_gaps()` `ensure_environment()` |
319
+ | 安装/信任(管理员) | `install()` `uninstall()` `run_elevated()` `trust(apply=...)` |
320
+ | 沙箱生命周期 | `session()` `run_once()` `start()` `current()` `run()` `stop()` `cleanup()` `list()` `prune()` `create()` `__enter__/__exit__` |
321
+ | 内核与服务 | `driver_status()` `kernel_ready()` `broker_status()` `broker_ping()` `broker_stress()` `broker_install()` |
322
+ | 浏览器 | `browser_config()` `browser_blockers()` `browser_arg_warnings()` |
323
+ | 验收 | `verify(live=...)` |
324
+ | 资源统计 | `resources(sandbox_id=None)` |
325
+
326
+ 构造函数:
327
+
328
+ ```python
329
+ SandboxManager(root=None, account=None, tier="auto", config=None, default_timeout=None,
330
+ preflight=True, preflight_ttl=60.0, ensure=True, elevation="never")
331
+ ```
332
+
333
+ ### 8.2 `Session` 与 `RunResult`
334
+
335
+ ```python
336
+ with winbox.session(name="demo", tier="appcontainer", config=None, cleanup_on_exit=True) as sb:
337
+ r = sb.run(["cmd.exe", "/c", "echo hi"], cwd=None, timeout=15)
338
+ print(r.ok, r.exit_code, r.stdout, r.stderr) # RunResult
339
+ print(sb.status()) # backend / store_dir / api_fake / 层状态
340
+ ```
341
+
342
+ `SandboxManager.session(...)` 额外支持 `report=`(单次是否打印检测报告)与 `auto_start=`(只构造不启动)。
343
+
344
+ ### 8.2.1 资源占用统计 `resources()`
345
+
346
+ ```python
347
+ with winbox.session("demo") as sb:
348
+ sb.run(["python", "-c", "buf = bytearray(64*1024*1024)"], timeout=30)
349
+ r = sb.resources() # 只读:不会启动沙箱
350
+ r["processes"] # {'total': 2, 'active': 0, 'terminated': 0, 'limit': 4}
351
+ r["cpu"] # {'user_ms': 1360.0, 'kernel_ms': 16.0, 'total_ms': 1376.0,
352
+ # 'rate_limit_percent': 50, 'job_time_limit_ms': None}
353
+ r["memory"] # {'peak_job_bytes': 90800000, 'peak_process_bytes': ..., 'working_set_bytes',
354
+ # 'private_bytes', 'page_faults', 'limit_job_bytes', 'limit_process_bytes'}
355
+ r["gpu"] # {'available': False, 'dedicated_bytes': None, 'shared_bytes': None,
356
+ # 'source': 'pdh:GPU Process Memory', 'reason': '...'}
357
+ r["disk"] # {'store_bytes', 'store_files', 'store_dirs',
358
+ # 'volume_free_bytes', 'volume_total_bytes'}
359
+ r["io"] # {'read_ops', 'write_ops', 'read_bytes', 'write_bytes'}
360
+ r["handles"], r["threads"], r["unavailable"] # 句柄数 / 线程数 / 每项测不到的原因
361
+ ```
362
+
363
+ 数据来源与**边界**:
364
+
365
+ * 进程数、CPU 时间、峰值内存、I/O 计数来自该沙箱自己的 **Job Object**,即**整棵进程树**的合计 ——
366
+ 所以它天然按沙箱隔离,一个沙箱一个 Job;
367
+ * 单进程视图(工作集/私有字节/句柄/线程)只在子进程**仍在运行**时可读;退出后是 `None` + 原因,
368
+ 因为 pid 会被系统复用,那时读出来的是别的进程;
369
+ * **显存**不在 Job Object 里:走性能计数器 `GPU Process Memory(pid_<pid>)`。没有 WDDM 适配器、
370
+ 进程当前没有 GPU 活动、或本机计数器不可用时,`gpu.available=False` 并写明原因 ——
371
+ **不用 0 冒充"没用显存"**;
372
+ * `memory_limit_mb` 是**单进程**上限(`limit_process_bytes`),Job 级上限(`limit_job_bytes`)
373
+ 只有显式配置时才有值;
374
+ * 硬盘是 store 整树字节/文件数 + 所在卷的空闲/总容量;
375
+ * `manager.resources(sandbox_id)` 用只读句柄统计:磁盘与 `state.json` 可读,而进程/CPU 属于创建
376
+ Job 的那个进程,若沙箱由别的进程启动则如实标为不可用并说明原因;没有活动会话时返回带原因的空结构,
377
+ 不抛异常。
378
+
379
+ ### 8.3 `SandboxConfig` 常用字段
380
+
381
+ ```python
382
+ from winbox import default_config
383
+ cfg = default_config("demo")
384
+ cfg.integrity = "low" # low(阻止写宿主用户目录) / medium(兼容更多程序)
385
+ cfg.elevation_policy = "appcontainer" # auto/appcontainer/restricted/jobonly(沙箱后端档位)
386
+ cfg.network = "none" # none/localhost/outbound/internet/full
387
+ cfg.memory_limit_mb = 512
388
+ cfg.cpu_rate_percent = 100
389
+ cfg.env_redirect = True # 把 C: 视图重定向到 store
390
+ cfg.api_fake = {"enabled": True}
391
+ ```
392
+
393
+ ### 8.4 模块级 API(与类同一实现)
394
+
395
+ ```python
396
+ import winbox
397
+ winbox.session(...) winbox.run_once(...) winbox.doctor() winbox.tiers() winbox.environment()
398
+ winbox.verify(live=True) winbox.broker_status() winbox.broker_stress() winbox.driver_status()
399
+ winbox.browser_arg_warnings([...]) winbox.browser_config()
400
+ ```
401
+
402
+ ### 8.5 异常
403
+
404
+ `winbox.SandboxError` 及其子类用于"启动/运行失败"的可捕获错误;环境不足一律走**报告 + 明确命令**,
405
+ 不用异常掩盖真实原因。
406
+
407
+ ---
408
+
409
+ ## 9. 示例
410
+
411
+ | 脚本 | 讲什么 |
412
+ |---|---|
413
+ | `01_quickstart.py` | 最小可用:建沙箱 → 跑命令 → 读 `ok/exit_code/stdout` |
414
+ | `02_tiers.py` | 四个档位的可用性与实际选中档 |
415
+ | `03_manager_preflight.py` | 单类入口:启动前检测报告 + 缺件自动补齐 |
416
+ | `04_files.py` | 沙箱内伪造 `C:`/`S:` 与宿主侧 store 的真实位置 |
417
+ | `05_browser.py` | 沙箱内跑 Chrome 的无头自检 + **禁止**的调试通道告警 |
418
+
419
+ ```powershell
420
+ python examples\01_quickstart.py
421
+ ```
422
+
423
+ 脚本自带 `sys.path` 引导,源码树里可直接运行;安装成包后那三行可删。
424
+
425
+ ---
426
+
427
+ ## 10. 已知限制(诚实清单)
428
+
429
+ **不得当作已通过**的部分:
430
+
431
+ 1. **`appcontainer` 档内浏览器的边界未测**:本机族内 Chrome 以 `0xC0000142` 退出,需在另一台底座正常的机器上补测;
432
+ 2. **内核闸门的"完整性判据"本身未测**:低于 Medium 的调用者**连控制端口都打不开**(两臂均为 `0x7f`),
433
+ 即**部署属性由端口 ACL 承担**;闸门内部的完整性规则未被实测证明(也未编译进出货镜像);
434
+ 闸门的**归属规则**(非盒主不得改盒策略)已实测有效;
435
+ 3. `restricted@medium` / `jobonly` **不阻止**写宿主用户目录 —— 这是档位语义,不是缺陷。
436
+
437
+ **路径名硬化**:store 路径分量若使用 Windows 保留设备名(`NUL`/`CON`/`COM1`/`aux.txt`…)、
438
+ 以点或空格结尾、或含 `<>:"/\|?*` 与不可见字符,`Session.path()` / `write_file()` **直接拒绝**。
439
+ 原因是这类名字一旦写进 store,Win32 就再也无法寻址它(`DeleteFileW`(123)、`\\?\` 形式、
440
+ `RemoveDirectoryW`、NT 相对打开、8.3 短名全部失败),会变成永久垃圾,连 store 清理都带不走。
441
+ store 删除路径同时采用健壮删除(重试 + 长路径 + 逐条目兜底,删不干净时报错而不是假装干净)。
442
+
443
+ ---
444
+
445
+ ## 11. 许可与责任
446
+
447
+ **专有许可:商用与个人使用都必须事先获得授权。** 本软件(源代码、二进制/驱动、文档、示例与随包载荷)
448
+ **默认不授予任何使用权** —— 无论**商业用途还是个人用途**,任何形式的使用都需要先取得版权持有人的**书面授权**。
449
+ 未获授权禁止复制、安装、部署、运行、修改、翻译、反编译(法律强制允许的情形除外)、分发、再许可、转售、
450
+ 以托管服务形式提供,或以任何方式使第三方获得;也不得移除版权与许可声明。完整条款见 [`LICENSE`](LICENSE);
451
+ 随包第三方组件(如 Dokan 运行时/驱动、Windows SDK 相关头文件)仍适用其各自许可,必须同时遵守。
452
+
453
+ 授权申请与商务联系:`<请填写版权持有人的联系方式>`。
454
+
455
+ **责任说明**:沙箱是**纵深防御的一部分** —— 请把"不受信任代码"当作"运行在你用户上下文里、受完整性/Job/
456
+ 受限令牌约束的程序"看待;涉及宿主敏感数据的场景请配合管理员 + AppContainer/Dokan 层并定期审计。所有
457
+ "能用/不能用"都由本机实测决定并如实报告:报告里出现 `SKIP/UNKNOWN` 时,那是**没有测到**,不是通过。
458
+ 本软件按"现状"提供,不附带任何担保,版权持有人不承担任何连带责任。