Repository navigation
feat(auth): recover the attach-instance launch token from process memory - #1
Merged
Merged
Conversation
added 3 commits
September 16, 2026 22:29
An attached dsh web has no console tail of ours to read, so reusing a running instance used to end at the restart-and-take-over prompt as soon as its 401 auth wall appeared. The shell now reads the launch token back out of the listener process and navigates with it. - new src-tauri/src/memtok.rs: raw kernel32 FFI, no new dependency; harvests maximal 43-char base64url runs plus the 32-byte tail-character constraint; three passes (skip MEM_IMAGE, then all memory, then all memory without the tail filter); 4MB chunks read by min(CPU,8) workers off an atomic range queue; probes every 16 candidates with early stop. A candidate is accepted only after a real HTTP exchange (303 + dsh-auth-* Set-Cookie) - shape is never proof - dsh.rs: check_auth_wall_now runs the recovery before the takeover prompt; at most two scans per run and the same token is never navigated twice, so an intercepting front-auth plugin cannot turn into a scan loop - the token never reaches the log: not landing on disk is the whole point of this auth - CI: build-shell.yml also runs on pull requests to prove the change compiles; the version bump and the release stay restricted to main
Measured on this machine's live 3080 instance with the reference PowerShell scanner: an unanchored whole-memory pass yields 656 candidates and the real token sat on the 649th probe, while the anchored pass (the printed URL's token=) sees single-digit candidates. Both numbers are now part of the design. - pass 1 scans only what follows the token= anchor; the unanchored passes stay as the reliable fallback, because the two scans are not subsets of each other (a token followed by base64url bytes is not a maximal run) - probe batches run on 8 lanes with an early stop, so a whole-memory pass no longer spends most of its time on serial HTTP round-trips - CHANGELOG records the measured baseline
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
attach(复用已有
dsh web实例)时,壳没有自己的子进程控制台尾可读,拿不到 launch token —— 于是只要 401 认证墙出现,就只能弹窗问用户「是否重启接管」。本次改成:先从运行中进程的内存里取回令牌并验证,失败才回退到原弹窗。
做法
新增
src-tauri/src/memtok.rs(纯kernel32裸 FFI,不加依赖;与lib.rs手写user32同风格):token=锚点之后的 43 字符,再退到「43 字符 base64url 的极大串」,附加尾字符约束AEIMQUYcgkosw048(43 字符编码 32 字节时末位只承载 4 bit,是长度带来的数学必然,不是对内容的猜测)dsh-auth-*cookie 的才算数(形状永不作为证据)四遍递进:锚点(跳 MEM_IMAGE)→ 极大串(跳 MEM_IMAGE)→ 极大串(全量)→ 极大串(去掉尾约束兜底)。
实测基线(决定了两个性能设计)
用参考 PowerShell 扫描器在本机真实的 3080 实例上实测:
两个数字直接影响了实现:
两种扫描不是包含关系(令牌后面紧跟 base64url 字节时它就不是极大串),所以锚点法不能取代裸扫描,只能排在前面。
安全
ReadProcessMemory),不写目标进程内存验证状态
本机没有 Rust 工具链,未做本地编译;编译由本 PR 的 CI 构建校验(
windows-latest+pnpm tauri build),首个 commit 的构建已经通过。运行期行为(能否真的扫到令牌)在本机无法验证——这是纯 Windows FFI 路径。算法逐条对齐了已在真实实例上验证过的 PowerShell 参考实现,上方基线数据即来自它。
CI 改动
build-shell.yml增加pull_request触发:PR 只构建并上传 exe 以校验可编译;版本递增与 Release 发布限定在 main(if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main')。