From 89c48131b258c68bc2c1e834f0afb564a7fac8b5 Mon Sep 17 00:00:00 2001 From: leefer Date: Sun, 2 Aug 2026 18:08:19 +0800 Subject: [PATCH] Initial commit --- .gitignore | 494 ++++++++++++++++ Directory.Build.props | 10 + NuGet.Config | 6 + README.md | 73 +++ WindowsToolbox.sln | 64 ++ assets/WindowsToolbox.ico | Bin 0 -> 41782 bytes assets/WindowsToolbox.png | Bin 0 -> 16969 bytes assets/WindowsToolbox.svg | 10 + data/kms-keys.json | 93 +++ docs/ARCHITECTURE.md | 53 ++ docs/OPERATIONS.md | 46 ++ global.json | 6 + scripts/build-release.ps1 | 51 ++ scripts/generate-icon.py | 62 ++ src/WindowsToolbox.App/App.xaml | 128 ++++ src/WindowsToolbox.App/App.xaml.cs | 12 + src/WindowsToolbox.App/AssemblyInfo.cs | 10 + src/WindowsToolbox.App/Converters.cs | 16 + src/WindowsToolbox.App/MainWindow.xaml | 351 +++++++++++ src/WindowsToolbox.App/MainWindow.xaml.cs | 21 + src/WindowsToolbox.App/ViewModels.cs | 550 ++++++++++++++++++ .../WindowsToolbox.App.csproj | 37 ++ src/WindowsToolbox.Cli/Program.cs | 20 + .../WindowsToolbox.Cli.csproj | 15 + src/WindowsToolbox.Core/Models.cs | 162 ++++++ .../WindowsToolbox.Core.csproj | 9 + src/WindowsToolbox.ElevatedHost/Program.cs | 74 +++ .../WindowsToolbox.ElevatedHost.csproj | 20 + src/WindowsToolbox.ElevatedHost/app.manifest | 16 + .../ActivationService.cs | 231 ++++++++ .../AppearanceService.cs | 176 ++++++ .../AutoLogonService.cs | 71 +++ .../CompanionLocator.cs | 32 + .../DesktopArchiveService.cs | 361 ++++++++++++ .../ElevatedCommandClient.cs | 98 ++++ .../JsonFileStore.cs | 74 +++ .../ProcessRunner.cs | 67 +++ .../RegistryStore.cs | 111 ++++ .../SnapshotStore.cs | 55 ++ .../SystemStatusService.cs | 127 ++++ .../TaskSchedulerService.cs | 160 +++++ .../ToolboxCommandDispatcher.cs | 127 ++++ .../WindowsSecurityService.cs | 209 +++++++ .../WindowsToolbox.Infrastructure.csproj | 13 + .../WindowsUpdateService.cs | 283 +++++++++ tests/WindowsToolbox.Verification/Program.cs | 124 ++++ .../WindowsToolbox.Verification.csproj | 15 + 47 files changed, 4743 insertions(+) create mode 100644 .gitignore create mode 100644 Directory.Build.props create mode 100644 NuGet.Config create mode 100644 README.md create mode 100644 WindowsToolbox.sln create mode 100644 assets/WindowsToolbox.ico create mode 100644 assets/WindowsToolbox.png create mode 100644 assets/WindowsToolbox.svg create mode 100644 data/kms-keys.json create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/OPERATIONS.md create mode 100644 global.json create mode 100644 scripts/build-release.ps1 create mode 100644 scripts/generate-icon.py create mode 100644 src/WindowsToolbox.App/App.xaml create mode 100644 src/WindowsToolbox.App/App.xaml.cs create mode 100644 src/WindowsToolbox.App/AssemblyInfo.cs create mode 100644 src/WindowsToolbox.App/Converters.cs create mode 100644 src/WindowsToolbox.App/MainWindow.xaml create mode 100644 src/WindowsToolbox.App/MainWindow.xaml.cs create mode 100644 src/WindowsToolbox.App/ViewModels.cs create mode 100644 src/WindowsToolbox.App/WindowsToolbox.App.csproj create mode 100644 src/WindowsToolbox.Cli/Program.cs create mode 100644 src/WindowsToolbox.Cli/WindowsToolbox.Cli.csproj create mode 100644 src/WindowsToolbox.Core/Models.cs create mode 100644 src/WindowsToolbox.Core/WindowsToolbox.Core.csproj create mode 100644 src/WindowsToolbox.ElevatedHost/Program.cs create mode 100644 src/WindowsToolbox.ElevatedHost/WindowsToolbox.ElevatedHost.csproj create mode 100644 src/WindowsToolbox.ElevatedHost/app.manifest create mode 100644 src/WindowsToolbox.Infrastructure/ActivationService.cs create mode 100644 src/WindowsToolbox.Infrastructure/AppearanceService.cs create mode 100644 src/WindowsToolbox.Infrastructure/AutoLogonService.cs create mode 100644 src/WindowsToolbox.Infrastructure/CompanionLocator.cs create mode 100644 src/WindowsToolbox.Infrastructure/DesktopArchiveService.cs create mode 100644 src/WindowsToolbox.Infrastructure/ElevatedCommandClient.cs create mode 100644 src/WindowsToolbox.Infrastructure/JsonFileStore.cs create mode 100644 src/WindowsToolbox.Infrastructure/ProcessRunner.cs create mode 100644 src/WindowsToolbox.Infrastructure/RegistryStore.cs create mode 100644 src/WindowsToolbox.Infrastructure/SnapshotStore.cs create mode 100644 src/WindowsToolbox.Infrastructure/SystemStatusService.cs create mode 100644 src/WindowsToolbox.Infrastructure/TaskSchedulerService.cs create mode 100644 src/WindowsToolbox.Infrastructure/ToolboxCommandDispatcher.cs create mode 100644 src/WindowsToolbox.Infrastructure/WindowsSecurityService.cs create mode 100644 src/WindowsToolbox.Infrastructure/WindowsToolbox.Infrastructure.csproj create mode 100644 src/WindowsToolbox.Infrastructure/WindowsUpdateService.cs create mode 100644 tests/WindowsToolbox.Verification/Program.cs create mode 100644 tests/WindowsToolbox.Verification/WindowsToolbox.Verification.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd2a271 --- /dev/null +++ b/.gitignore @@ -0,0 +1,494 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET +project.lock.json +project.fragment.lock.json +artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp + +# Repository-local SDK and release artifacts +.tools/ +artifacts/ + +# The macOS *.app rule above also matches this WPF project on Windows. +!src/WindowsToolbox.App/ +!src/WindowsToolbox.App/*.cs +!src/WindowsToolbox.App/*.xaml +!src/WindowsToolbox.App/*.csproj diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..96140df --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,10 @@ + + + latest + enable + enable + false + true + $(MSBuildThisFileDirectory)assets\WindowsToolbox.ico + + diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..a3f3aea --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..b0e9071 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Windows 工具箱 + +面向 Windows 10/11 的中文 WPF 系统工具。主程序以普通权限运行;修改系统设置时才启动独立管理员执行器。所有可恢复功能会在第一次修改前保存基线快照,重复执行不会覆盖原始状态。 + +## 已实现功能 + +- Windows 11 经典右键菜单:启用、恢复;修改后自动重启 Explorer,在 Build 26200 上立即生效。 +- 快捷方式箭头:隐藏、恢复,并生成本地透明图标资源。 +- Windows 更新:暂停 1—35 天、每日自动续期、强力关闭、每日关闭守护、恢复原始状态。 +- Windows 安全:检测防篡改保护、关闭可控制的 Defender 防护、可选关闭防火墙、恢复原始设置。 +- 自动登录:恢复 `netplwiz` 中可能隐藏的密码复选框并打开 Windows 自带账户控制;工具不读取密码。 +- 桌面归档:使用 Known Folder API 识别真实桌面,按 `yyyy-MM-dd` 归档普通文件和普通文件夹;排除快捷方式、系统项及重解析目录,自动处理同名文件/文件夹,支持撤销和每月计划任务。 +- KMS:内置微软公开的 Windows 10/11 GVLK,使用用户填写的本地 KMS 地址,连接成功后才安装密钥,支持恢复原 KMS 主机。 +- 系统状态、逐步执行结果及最近 100 次操作历史。 +- 多尺寸应用图标,同时用于窗口标题栏、任务栏和 EXE 文件。 + +启动时只运行一个有 5 秒硬超时的可选状态查询进程,主窗口不会等待它才显示;普通功能完成后只刷新注册表基础状态,不再重复等待 Defender 与许可证查询。 + +## 运行 + +开发构建输出位于: + +```text +src\WindowsToolbox.App\bin\Debug\net8.0-windows\WindowsToolbox.App.exe +``` + +发布目录生成后运行: + +```text +artifacts\WindowsToolbox\WindowsToolbox.App.exe +``` + +运行环境需要 Windows 10/11 x64 和 .NET 8 Desktop Runtime。涉及系统修改的按钮会出现 UAC 提示。 + +## 构建 + +仓库已经配置本地 .NET 8 SDK 位置。执行: + +```powershell +.\scripts\build-release.ps1 +``` + +生成便携发布目录: + +```text +artifacts\WindowsToolbox\ +``` + +项目没有第三方 NuGet 运行依赖。 + +## 数据位置 + +```text +%LOCALAPPDATA%\WindowsToolbox\ +├─ ArchiveManifests\ 桌面归档恢复清单 +├─ Logs\ 操作历史 +├─ Pending\ 临时提权命令及结果 +└─ Profiles\ 桌面归档配置 + +%PROGRAMDATA%\WindowsToolbox\ +├─ Assets\ 透明快捷方式图标 +└─ Snapshots\ 系统设置基线快照 +``` + +## 重要边界 + +- “强力关闭更新”会关闭可控制的策略、服务和任务,并每日重新检查;Windows 就地修复或重大升级后仍可能恢复受保护组件。 +- 工具不会绕过 Defender 防篡改保护。关闭 Defender 前必须由用户在 Windows 安全中心手动关闭防篡改保护。 +- 家庭版不支持 KMS 客户端激活。Windows 客户端的正规 KMS 服务还需要满足微软规定的客户端数量门槛。 +- KMS 恢复功能可以恢复主机和端口,但 Windows 不提供旧完整产品密钥,无法自动恢复未知旧密钥。 +- 跨磁盘文件移动不是文件系统原子操作;移动失败会保留在恢复清单和操作日志中。 + +更多内部设计见 [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) 和 [docs/OPERATIONS.md](docs/OPERATIONS.md)。 diff --git a/WindowsToolbox.sln b/WindowsToolbox.sln new file mode 100644 index 0000000..f83aed0 --- /dev/null +++ b/WindowsToolbox.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E54A5670-8E0E-463E-8FBF-430054BF2736}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.Core", "src\WindowsToolbox.Core\WindowsToolbox.Core.csproj", "{404532FF-0F8C-4A80-A182-3FEBAB789DC3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.Infrastructure", "src\WindowsToolbox.Infrastructure\WindowsToolbox.Infrastructure.csproj", "{32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.App", "src\WindowsToolbox.App\WindowsToolbox.App.csproj", "{44AEEFE7-C6CA-482D-BDDF-54F5CF570295}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.ElevatedHost", "src\WindowsToolbox.ElevatedHost\WindowsToolbox.ElevatedHost.csproj", "{61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.Cli", "src\WindowsToolbox.Cli\WindowsToolbox.Cli.csproj", "{BC9B81D5-0862-4465-9357-738BB0B2E4E0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{A98D294C-F010-49CE-968F-A85E2F921692}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsToolbox.Verification", "tests\WindowsToolbox.Verification\WindowsToolbox.Verification.csproj", "{8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {404532FF-0F8C-4A80-A182-3FEBAB789DC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {404532FF-0F8C-4A80-A182-3FEBAB789DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {404532FF-0F8C-4A80-A182-3FEBAB789DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {404532FF-0F8C-4A80-A182-3FEBAB789DC3}.Release|Any CPU.Build.0 = Release|Any CPU + {32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4}.Release|Any CPU.Build.0 = Release|Any CPU + {44AEEFE7-C6CA-482D-BDDF-54F5CF570295}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44AEEFE7-C6CA-482D-BDDF-54F5CF570295}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44AEEFE7-C6CA-482D-BDDF-54F5CF570295}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44AEEFE7-C6CA-482D-BDDF-54F5CF570295}.Release|Any CPU.Build.0 = Release|Any CPU + {61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22}.Release|Any CPU.Build.0 = Release|Any CPU + {BC9B81D5-0862-4465-9357-738BB0B2E4E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC9B81D5-0862-4465-9357-738BB0B2E4E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC9B81D5-0862-4465-9357-738BB0B2E4E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC9B81D5-0862-4465-9357-738BB0B2E4E0}.Release|Any CPU.Build.0 = Release|Any CPU + {8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {404532FF-0F8C-4A80-A182-3FEBAB789DC3} = {E54A5670-8E0E-463E-8FBF-430054BF2736} + {32D8C232-E015-4DC5-8DF6-D9B6C70D2BC4} = {E54A5670-8E0E-463E-8FBF-430054BF2736} + {44AEEFE7-C6CA-482D-BDDF-54F5CF570295} = {E54A5670-8E0E-463E-8FBF-430054BF2736} + {61D6B7B9-FB16-4D3C-B0FA-1EE6B5124E22} = {E54A5670-8E0E-463E-8FBF-430054BF2736} + {BC9B81D5-0862-4465-9357-738BB0B2E4E0} = {E54A5670-8E0E-463E-8FBF-430054BF2736} + {8CCFF617-CDF1-4EFD-812E-AE92CD75F8CA} = {A98D294C-F010-49CE-968F-A85E2F921692} + EndGlobalSection +EndGlobal diff --git a/assets/WindowsToolbox.ico b/assets/WindowsToolbox.ico new file mode 100644 index 0000000000000000000000000000000000000000..f668d8107ead1490bd4961c5e971a538031298a3 GIT binary patch literal 41782 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%0AF9m*H)I5XDpleR~aJ9p^ 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 literal 0 HcmV?d00001 diff --git a/assets/WindowsToolbox.svg b/assets/WindowsToolbox.svg new file mode 100644 index 0000000..a540d7a --- /dev/null +++ b/assets/WindowsToolbox.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/data/kms-keys.json b/data/kms-keys.json new file mode 100644 index 0000000..98ea972 --- /dev/null +++ b/data/kms-keys.json @@ -0,0 +1,93 @@ +[ + { + "editionId": "Professional", + "displayName": "Windows 10/11 专业版", + "productKey": "W269N-WFGWX-YVC9B-4J6C9-T83GX", + "appliesTo": "Windows 10/11 Pro" + }, + { + "editionId": "ProfessionalN", + "displayName": "Windows 10/11 专业版 N", + "productKey": "MH37W-N47XK-V7XM9-C7227-GCQG9", + "appliesTo": "Windows 10/11 Pro N" + }, + { + "editionId": "ProfessionalWorkstation", + "displayName": "Windows 10/11 专业工作站版", + "productKey": "NRG8B-VKK3Q-CXVCJ-9G2XF-6Q84J", + "appliesTo": "Windows 10/11 Pro for Workstations" + }, + { + "editionId": "ProfessionalWorkstationN", + "displayName": "Windows 10/11 专业工作站版 N", + "productKey": "9FNHH-K3HBT-3W4TD-6383H-6XYWF", + "appliesTo": "Windows 10/11 Pro for Workstations N" + }, + { + "editionId": "ProfessionalEducation", + "displayName": "Windows 10/11 专业教育版", + "productKey": "6TP4R-GNPTD-KYYHQ-7B7DP-J447Y", + "appliesTo": "Windows 10/11 Pro Education" + }, + { + "editionId": "ProfessionalEducationN", + "displayName": "Windows 10/11 专业教育版 N", + "productKey": "YVWGF-BXNMC-HTQYQ-CPQ99-66QFC", + "appliesTo": "Windows 10/11 Pro Education N" + }, + { + "editionId": "Education", + "displayName": "Windows 10/11 教育版", + "productKey": "NW6C2-QMPVW-D7KKK-3GKT6-VCFB2", + "appliesTo": "Windows 10/11 Education" + }, + { + "editionId": "EducationN", + "displayName": "Windows 10/11 教育版 N", + "productKey": "2WH4N-8QGBV-H22JP-CT43Q-MDWWJ", + "appliesTo": "Windows 10/11 Education N" + }, + { + "editionId": "Enterprise", + "displayName": "Windows 10/11 企业版", + "productKey": "NPPR9-FWDCX-D2C8J-H872K-2YT43", + "appliesTo": "Windows 10/11 Enterprise" + }, + { + "editionId": "EnterpriseN", + "displayName": "Windows 10/11 企业版 N", + "productKey": "DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4", + "appliesTo": "Windows 10/11 Enterprise N" + }, + { + "editionId": "EnterpriseG", + "displayName": "Windows 10/11 企业版 G", + "productKey": "YYVX9-NTFWV-6MDM3-9PT4T-4M68B", + "appliesTo": "Windows 10/11 Enterprise G" + }, + { + "editionId": "EnterpriseGN", + "displayName": "Windows 10/11 企业版 G N", + "productKey": "44RPN-FTY23-9VTTB-MP9BX-T84FV", + "appliesTo": "Windows 10/11 Enterprise G N" + }, + { + "editionId": "EnterpriseS", + "displayName": "Windows 10/11 企业版 LTSC", + "productKey": "M7XTQ-FN8P6-TTKYV-9D4CC-J462D", + "appliesTo": "Enterprise LTSC 2019/2021/2024" + }, + { + "editionId": "EnterpriseSN", + "displayName": "Windows 10/11 企业版 LTSC N", + "productKey": "92NFX-8DJQP-P6BBQ-THF9C-7CG2H", + "appliesTo": "Enterprise LTSC N 2019/2021/2024" + }, + { + "editionId": "Core", + "displayName": "Windows 家庭版(不支持 KMS 客户端激活)", + "productKey": "", + "appliesTo": "Windows 10/11 Home", + "supported": false + } +] diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..37fcf4c --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,53 @@ +# 架构说明 + +## 项目组成 + +```text +WindowsToolbox.App + WPF 界面、MVVM、UAC 客户端 + +WindowsToolbox.ElevatedHost + 固定命令白名单、管理员权限系统修改 + +WindowsToolbox.Cli + 当前用户桌面归档计划任务入口 + +WindowsToolbox.Infrastructure + 注册表、进程、任务计划、快照、各功能实现 + +WindowsToolbox.Core + 命令、状态、结果、快照和配置模型 + +WindowsToolbox.Verification + 不修改系统的自动验证程序 +``` + +## 执行流程 + +```text +用户点击功能 + → 主程序生成强类型 ToolboxCommand + → 普通文件操作直接执行 + → 系统操作写入 Pending 目录并请求 UAC + → ElevatedHost 验证路径、时效和命令类型 + → 首次操作保存基线快照 + → 执行固定实现 + → 读取实际状态进行验证 + → 写入结果和操作历史 + → 主程序刷新系统状态 +``` + +管理员执行器只接受枚举中的命令以及经过各模块验证的参数,不提供任意 CMD、PowerShell 或脚本执行入口。 + +## 扩展新功能 + +新增功能时应按以下顺序: + +1. 在 `ToolboxCommandKind` 中添加固定命令。 +2. 在基础设施项目中实现模块服务。 +3. 确定原始状态的完整快照范围。 +4. 在 `ToolboxCommandDispatcher` 注册执行分支和提权要求。 +5. 在 WPF ViewModel 暴露命令,在页面添加状态、风险说明、应用和恢复入口。 +6. 向 Verification 项目增加非破坏性验证。 + +每个修改操作必须满足幂等、可验证和尽可能可恢复;不能只根据进程退出码显示成功。 diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md new file mode 100644 index 0000000..86c296d --- /dev/null +++ b/docs/OPERATIONS.md @@ -0,0 +1,46 @@ +# 系统操作边界 + +## 右键菜单与快捷方式箭头 + +经典菜单使用当前用户 Shell 类注册项,并在修改后由普通权限主程序自动重启 Explorer。检测到 Atlas OS 时,同时维护 Atlas Toolbox 使用的状态镜像,实际状态仍以 Explorer 读取的 CLSID 项为准。快捷方式箭头使用系统 `Shell Icons` 覆盖值和工具生成的透明 ICO。 + +## Windows 更新 + +强力关闭模式管理: + +- Windows Update 自动更新策略。 +- `wuauserv`、`UsoSvc` 和 `WaaSMedicSvc` 的可控制启动状态。 +- Update Orchestrator 与 Windows Update 中存在且允许修改的计划任务。 +- `WindowsToolbox\UpdateGuard` 每日守护任务。 + +部分服务和任务在不同 Windows 构建中受系统保护。模块会保留每一步结果,不把拒绝访问伪装成成功。 + +暂停模式写入开始和结束时间,最长限制为 35 天。自动续期任务每天重新请求所选暂停长度并再次验证。 + +## Windows 安全 + +模块使用 Defender 和防火墙的 Windows PowerShell Cmdlet。它不会停止 Security Center 核心服务,不会修改系统文件所有权,也不会绕过防篡改保护。恢复时按基线快照逐项恢复 Defender 偏好、三个防火墙配置和通知策略。 + +## 桌面归档 + +枚举桌面根目录中的文件和文件夹。默认排除: + +- `desktop.ini` +- `.lnk` 和 `.url` +- 带 System 属性的文件或文件夹 +- 重解析点、目录联接及其他可能指向桌面外部的特殊目录 + +普通隐藏文件会归档。虚拟的“此电脑”“回收站”等系统图标不属于文件系统枚举范围,因此不会移动。同名目标采用 `名称 (1).扩展名` 或 `文件夹 (1)` 递增。每次执行都生成恢复清单;撤销只移动仍然存在于归档目录中的项目。 + +## KMS + +密钥目录位于 `data\kms-keys.json`,可以手动维护。激活顺序为: + +1. 验证版本、密钥格式、主机和端口。 +2. TCP 测试本地 KMS 主机。 +3. 保存原 KMS 主机和端口。 +4. 安装所选 GVLK。 +5. 设置 KMS 主机。 +6. 请求 Windows 激活。 + +如果连接测试失败,不修改产品密钥。 diff --git a/global.json b/global.json new file mode 100644 index 0000000..4a8c056 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.423", + "rollForward": "latestPatch" + } +} diff --git a/scripts/build-release.ps1 b/scripts/build-release.ps1 new file mode 100644 index 0000000..c8e5001 --- /dev/null +++ b/scripts/build-release.ps1 @@ -0,0 +1,51 @@ +param( + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + [switch]$SkipRestore +) + +$ErrorActionPreference = 'Stop' +$projectRoot = Split-Path -Parent $PSScriptRoot +$dotnetExe = Join-Path $projectRoot '.tools\dotnet\dotnet.exe' +$nugetConfig = Join-Path $projectRoot 'NuGet.Config' +$outputRoot = Join-Path $projectRoot 'artifacts\WindowsToolbox' + +if (-not (Test-Path -LiteralPath $dotnetExe)) { + throw 'Local .NET SDK was not found under .tools\dotnet.' +} + +$env:DOTNET_CLI_HOME = Join-Path $projectRoot '.tools\dotnet-home' +$env:NUGET_PACKAGES = Join-Path $projectRoot '.tools\nuget' +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' +$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' + +New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null + +if (-not $SkipRestore) { + & $dotnetExe restore (Join-Path $projectRoot 'WindowsToolbox.sln') --configfile $nugetConfig + if ($LASTEXITCODE -ne 0) { throw 'Restore failed.' } +} + +$commonArguments = @( + '--configuration', $Configuration, + '--framework', 'net8.0-windows', + '--self-contained', 'false', + '--no-restore', + '--output', $outputRoot, + '-p:DebugType=None', + '-p:DebugSymbols=false' +) + +& $dotnetExe publish (Join-Path $projectRoot 'src\WindowsToolbox.ElevatedHost\WindowsToolbox.ElevatedHost.csproj') @commonArguments +if ($LASTEXITCODE -ne 0) { throw 'Elevated host publish failed.' } + +& $dotnetExe publish (Join-Path $projectRoot 'src\WindowsToolbox.Cli\WindowsToolbox.Cli.csproj') @commonArguments +if ($LASTEXITCODE -ne 0) { throw 'CLI publish failed.' } + +& $dotnetExe publish (Join-Path $projectRoot 'src\WindowsToolbox.App\WindowsToolbox.App.csproj') @commonArguments +if ($LASTEXITCODE -ne 0) { throw 'WPF app publish failed.' } + +Copy-Item -LiteralPath (Join-Path $projectRoot 'README.md') -Destination (Join-Path $outputRoot 'README.md') -Force + +Write-Host "Published to: $outputRoot" -ForegroundColor Green +Write-Host 'Run WindowsToolbox.App.exe to start.' -ForegroundColor Green diff --git a/scripts/generate-icon.py b/scripts/generate-icon.py new file mode 100644 index 0000000..b34216e --- /dev/null +++ b/scripts/generate-icon.py @@ -0,0 +1,62 @@ +from pathlib import Path + +from PIL import Image, ImageDraw + + +ROOT = Path(__file__).resolve().parents[1] +ASSETS = ROOT / "assets" +SCALE = 4 +SIZE = 256 +CANVAS = SIZE * SCALE + + +def scaled_points(points): + return [(x * SCALE, y * SCALE) for x, y in points] + + +mask = Image.new("L", (CANVAS, CANVAS), 0) +mask_draw = ImageDraw.Draw(mask) +mask_draw.rounded_rectangle( + (8 * SCALE, 8 * SCALE, 248 * SCALE, 248 * SCALE), + radius=54 * SCALE, + fill=255, +) + +background = Image.new("RGBA", (CANVAS, CANVAS), (0, 0, 0, 0)) +pixels = background.load() +for y in range(CANVAS): + ratio = y / max(1, CANVAS - 1) + red = round(59 + (29 - 59) * ratio) + green = round(130 + (78 - 130) * ratio) + blue = round(246 + (216 - 246) * ratio) + for x in range(CANVAS): + pixels[x, y] = (red, green, blue, mask.getpixel((x, y))) + +draw = ImageDraw.Draw(background, "RGBA") +highlight = Image.new("RGBA", (CANVAS, CANVAS), (0, 0, 0, 0)) +highlight_draw = ImageDraw.Draw(highlight, "RGBA") +highlight_draw.ellipse( + (-60 * SCALE, -110 * SCALE, 250 * SCALE, 150 * SCALE), + fill=(255, 255, 255, 22), +) +background.alpha_composite(highlight) + +w_shape = [ + (44, 66), (78, 66), (105, 157), (128, 98), + (129, 98), (152, 157), (179, 66), (212, 66), + (174, 192), (139, 192), (128, 161), (116, 192), + (82, 192), +] +shadow_shape = [(x, y + 4) for x, y in w_shape] +draw.polygon(scaled_points(shadow_shape), fill=(10, 35, 90, 45)) +draw.polygon(scaled_points(w_shape), fill=(255, 255, 255, 255)) + +icon = background.resize((SIZE, SIZE), Image.Resampling.LANCZOS) +ASSETS.mkdir(parents=True, exist_ok=True) +icon.save(ASSETS / "WindowsToolbox.png", "PNG", optimize=True) +icon.save( + ASSETS / "WindowsToolbox.ico", + "ICO", + sizes=[(16, 16), (20, 20), (24, 24), (32, 32), (40, 40), (48, 48), (64, 64), (128, 128), (256, 256)], +) +print(ASSETS / "WindowsToolbox.ico") diff --git a/src/WindowsToolbox.App/App.xaml b/src/WindowsToolbox.App/App.xaml new file mode 100644 index 0000000..a6e8557 --- /dev/null +++ b/src/WindowsToolbox.App/App.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/WindowsToolbox.App/App.xaml.cs b/src/WindowsToolbox.App/App.xaml.cs new file mode 100644 index 0000000..9e5c2c2 --- /dev/null +++ b/src/WindowsToolbox.App/App.xaml.cs @@ -0,0 +1,12 @@ +using System.Configuration; +using System.Data; +using System.Windows; + +namespace WindowsToolbox.App; + +/// +/// Interaction logic for App.xaml +/// +public partial class App : Application +{ +} diff --git a/src/WindowsToolbox.App/AssemblyInfo.cs b/src/WindowsToolbox.App/AssemblyInfo.cs new file mode 100644 index 0000000..cc29e7f --- /dev/null +++ b/src/WindowsToolbox.App/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/src/WindowsToolbox.App/Converters.cs b/src/WindowsToolbox.App/Converters.cs new file mode 100644 index 0000000..b50e311 --- /dev/null +++ b/src/WindowsToolbox.App/Converters.cs @@ -0,0 +1,16 @@ +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace WindowsToolbox.App; + +public sealed class PageVisibilityConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => + string.Equals(value?.ToString(), parameter?.ToString(), StringComparison.OrdinalIgnoreCase) + ? Visibility.Visible + : Visibility.Collapsed; + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => + Binding.DoNothing; +} diff --git a/src/WindowsToolbox.App/MainWindow.xaml b/src/WindowsToolbox.App/MainWindow.xaml new file mode 100644 index 0000000..5c32741 --- /dev/null +++ b/src/WindowsToolbox.App/MainWindow.xaml @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +