6.3 KiB
6.3 KiB
title, type, permalink, stable_id, scope, project_id, memory_type, status, revision, restored_from_commit, created_at, updated_at, tags
| title | type | permalink | stable_id | scope | project_id | memory_type | status | revision | restored_from_commit | created_at | updated_at | tags | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Checkpoint 2026-08-20 02:00:50 UTC [d8e18b60e5] | checkpoint | main/projects/ea207d36-693c-4349-b3c8-7c40c8c889f5/checkpoint-2026-08-20-02-00-50-utc-d8e18b60e5 | 715e4eb8-48b7-4540-9a75-5be72eeb0c7e | project | ea207d36-693c-4349-b3c8-7c40c8c889f5 | checkpoint | active | 1 | 6a6a895eaf |
2026-09-23T15:11:30.800050+00:00 | 2026-09-23T15:11:30.800102+00:00 |
|
WinUnLock 完整工程实现完成(编译通过 + 导出验证 + 首次提交)
完成内容
在 E:\code\WinUnLock 从零落地了完整可编译工程,30 个文件、3701 行,首次提交 3e4d09b(分支 main)。
四个 crate(包名即产物名)
- common(rlib):protocol.rs 管道协议 v1 编解码(magic 0x554E4C4B/version 1,单字段上限 64KiB)、config.rs(serde+toml)、dpapi.rs(CryptProtectData/CryptUnprotectData,LocalMachine 作用域 + 固定 entropy "WinUnLock::DPAPI::v1")、account.rs(域\用户 解析)、paths.rs(%PROGRAMDATA%\WinUnLock)、error.rs(thiserror)
- provider(cdylib → provider.dll):lib.rs(导出+类工厂)、provider.rs(ICredentialProvider)、credential.rs(ICredentialProviderCredential + CredPack + LSA Negotiate 包查询)、pipe.rs(管道服务端)、registration.rs(自注册)、logging.rs(轻量文件日志)、shared.rs
- client(bin → client.exe):读 config+cred.bin,WaitNamedPipeW+CreateFileW+WriteFile 发送,带重试
- setup(bin → setup.exe):交互式设置,用 SetConsoleMode 关闭 ENABLE_ECHO_INPUT 实现密码不回显(未引入 rpassword 依赖)
关键实现决策
- 有意不设 panic="abort":provider.dll 跑在 LogonUI 内,abort 会拖垮登录界面。改为在 DllMain/导出函数/管道线程用 catch_unwind 兜底,满足「确保 FFI 边界不展开」。已在根 Cargo.toml 注释说明理由。
- 只在 CPUS_UNLOCK_WORKSTATION 返回 S_OK,其余场景(含 CPUS_LOGON)返回 E_NOTIMPL,彻底不干扰正常登录/改密。
- 不抢默认磁贴:凭据未送达时 GetCredentialCount 把 pdwdefault 设为 0xFFFFFFFF 且 autologon=false,保证用户仍能手动解锁;凭据送达后才置 0 + true。
- 管道:PIPE_ACCESS_INBOUND|FILE_FLAG_FIRST_PIPE_INSTANCE,PIPE_TYPE_MESSAGE|READMODE_MESSAGE|WAIT|PIPE_REJECT_REMOTE_CLIENTS,nMaxInstances=1,SDDL
D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)(D;;GA;;;AN)(D;;GA;;;NU)(沿用 hodor 思路)。Drop 时靠「自连接 CreateFileW(GENERIC_WRITE)」唤醒阻塞的 ConnectNamedPipe。 - GetSerialization 成功后立即 zeroize 共享密码并把 ready 置回 false(一次性凭据)。
编译期踩到并已修复的 windows 0.62.2 API 差异(重要经验)
GetLocalTime()无出参,直接返回 SYSTEMTIME(不是 C 风格GetLocalTime(&mut st))。WaitNamedPipeW返回 BOOL(用.as_bool()),不是 Result。- DPAPI 签名验证正确:
CryptProtectData(&in_blob, PCWSTR::null(), Some(&entropy), None, None, u32_flags, &mut out);CryptUnprotectData第 2 参是Option<*mut PWSTR>传 None。dwflags 是裸 u32。输出 blob 需 LocalFree。 RegCreateKeyExW/RegSetValueExW的 reserved 参数在 0.62.2 里是 Option 类型(传 None,不是 0)。GetModuleFileNameW(Some(hmodule), &mut buf)第一参是 Option。
验证结果
cargo build --release --target x86_64-pc-windows-msvc通过,零警告。产物:provider.dll 586752 B、client.exe 518656 B、setup.exe 647680 B。cargo test14 个测试全过(协议往返/错误magic/错误version/超长字段/截断数据/Debug不泄露密码/账户解析×4/配置往返/DPAPI往返/GUID格式化)。DPAPI 往返实测通过,证明 LocalMachine+entropy 组合可用。- dumpbin /exports 确认 provider.dll 正确导出 5 个函数:DllCanUnloadNow、DllGetClassObject、DllMain、DllRegisterServer、DllUnregisterServer(cdylib 自动导出,无需 .def,已在 .cargo/config.toml 注释说明)。
遇到的坑与解决
- rust-toolchain.toml 写死 channel="1.94.1" 会触发 rustup 联网重装整条工具链,本机 1.94.1 目录处于「部分安装」状态,导致 rename 失败(os error 145 目录不是空的)并反复重试。已改为
channel = "stable"(本机 stable 即 1.94.1)。该文件在 rustup 回滚过程中被清掉过一次,重写后已确认存在并进入提交。 - 昨天中断留下的 3 个占位 stub(winunlock-provider/client/setup,引用不存在的 winunlock-common)导致 cargo 无法解析 workspace,已全部用真实实现覆盖,包名统一为 common/provider/client/setup,使产物直接叫 provider.dll/client.exe/setup.exe,与 install.ps1 和 provider.reg 对齐。
边界遵守情况(已实测确认)
全程只做代码编写 + cargo build/test + dumpbin。已验证:%PROGRAMDATA%\WinUnLock 不存在、注册表 CLSID 项不存在、计划任务不存在。未执行任何 regsvr32/改注册表/建计划任务/复制文件到 ProgramData。
下一步 / 给下个会话
- 端到端真机流程尚未验证,必须由用户在虚拟机里测:先拍快照 → 管理员跑 install.ps1(可用 -UnlockTime 定在 1~2 分钟后)→ 跑 bin\setup.exe 设账户密码 → Win+L 锁屏 → 观察是否自动解锁 → 看 logs\provider.log 与 client.log。
- 若 VM 测试失败,优先怀疑三处:(a) GetSerialization 的 ulAuthenticationPackage(Negotiate 包 ID 查询失败会退回 0);(b) 是否真的走到 GetCredentialCount 的 autologon 分支(看 provider.log 有无「凭据已就绪,请求自动登录」);(c) 域账户时 full_username 拼接是否符合 LSA 期望。
- 故障恢复要点已写进 README 第 8 节:删
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{E9C67B30-B120-4838-A5A3-FBC2DE03C532}(决定性的一个)与HKLM\SOFTWARE\Classes\CLSID\{同上};含安全模式方案与 WinRE 下reg load HKLM\WULOCK离线删除方案(注意挂载后路径里没有 SOFTWARE\ 这一层)。 - 已知限制:仅支持账户文本密码(Windows Hello PIN 不适用);睡眠/休眠下不会唤醒机器;client 退出码 10 = 管道不存在(通常只是当时没锁屏,属正常)。