Files
MemRelay/projects/ea207d36-693c-4349-b3c8-7c40c8c889f5/Checkpoint 2026-08-20 02-00-50 UTC [d8e18b60e5].md
T

64 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Checkpoint 2026-08-20 02:00:50 UTC [d8e18b60e5]
type: checkpoint
permalink: main/projects/ea207d36-693c-4349-b3c8-7c40c8c889f5/checkpoint-2026-08-20-02-00-50-utc-d8e18b60e5
stable_id: 715e4eb8-48b7-4540-9a75-5be72eeb0c7e
scope: project
project_id: ea207d36-693c-4349-b3c8-7c40c8c889f5
memory_type: checkpoint
status: active
revision: 1
restored_from_commit: 6a6a895eafcca6052e81a14fca103a42635dd1c2
created_at: '2026-09-23T15:11:30.800050+00:00'
updated_at: '2026-09-23T15:11:30.800102+00:00'
tags:
- 实现完成
- credential-provider
- rust
- 编译通过
- 待VM验证
---
# 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 差异(重要经验)
1. `GetLocalTime()` **无出参**,直接返回 SYSTEMTIME(不是 C 风格 `GetLocalTime(&mut st)`)。
2. `WaitNamedPipeW` 返回 **BOOL**(用 `.as_bool()`),不是 Result。
3. DPAPI 签名验证正确:`CryptProtectData(&in_blob, PCWSTR::null(), Some(&entropy), None, None, u32_flags, &mut out)`;`CryptUnprotectData` 第 2 参是 `Option<*mut PWSTR>` 传 None。dwflags 是裸 u32。输出 blob 需 LocalFree。
4. `RegCreateKeyExW`/`RegSetValueExW` 的 reserved 参数在 0.62.2 里是 **Option 类型**(传 None,不是 0)。
5. `GetModuleFileNameW(Some(hmodule), &mut buf)` 第一参是 Option<HMODULE>。
## 验证结果
- `cargo build --release --target x86_64-pc-windows-msvc` **通过,零警告**。产物:provider.dll 586752 B、client.exe 518656 B、setup.exe 647680 B。
- `cargo test` **14 个测试全过**(协议往返/错误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。
## 下一步 / 给下个会话
1. **端到端真机流程尚未验证**,必须由用户在虚拟机里测:先拍快照 → 管理员跑 install.ps1(可用 -UnlockTime 定在 1~2 分钟后)→ 跑 bin\setup.exe 设账户密码 → Win+L 锁屏 → 观察是否自动解锁 → 看 logs\provider.log 与 client.log。
2. 若 VM 测试失败,优先怀疑三处:(a) GetSerialization 的 ulAuthenticationPackage(Negotiate 包 ID 查询失败会退回 0);(b) 是否真的走到 GetCredentialCount 的 autologon 分支(看 provider.log 有无「凭据已就绪,请求自动登录」);(c) 域账户时 full_username 拼接是否符合 LSA 期望。
3. 故障恢复要点已写进 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\ 这一层)。
4. 已知限制:仅支持账户文本密码(Windows Hello PIN 不适用);睡眠/休眠下不会唤醒机器;client 退出码 10 = 管道不存在(通常只是当时没锁屏,属正常)。