第6篇:从技术到产品 — Ghost Proxifier 的设计哲学

0 阅读7分钟

第6篇:从技术到产品 — Ghost Proxifier 的设计哲学

系列:《从0到1搭建一个自己的Proxifier》 上一篇:第5篇《Cygwin 兼容之战 — 一次 SIGSEGV 的排查之旅》 (系列终篇)


一、技术走通只是 50%

核心引擎在我的开发机上跑得比预期好。SetThreadContext 注入完美、进程树自动追踪、Cygwin 兼容——技术上基本没有解决不了的问题。

我很兴奋,打了个 zip 包发给几个朋友。

反馈是这样的:

"解压了……然后呢?" "这么多文件,哪个是 exe?" "点开报错,缺 WebView2 运行时。"

我意识到:我自己用了几个月的东西,对别人来说就是一堆没有面孔的文件。技术走通了,但离"能用"还有巨大的鸿沟。

程序员有一个通病——觉得自己理解了的东西,用户也应该理解。我花了几天写 shellcode,用户凭什么要知道 PID 是什么?我调试了 Cygwin 的 TLS,用户凭什么要理解"注入方式"?

做产品和做技术的区别,就是前者在问一个问题:用你东西的那个人,此刻在想什么?


二、GUI vs 命令行:不是技术决策,是用户决策

很多技术朋友问我:一个代理工具为什么做 GUI?proxychains-ng 一个命令就搞定了,不香吗?

香,对开发者来说。但 Ghost Proxifier 的主要目标用户不是开发者。

想象一个做出海电商运营的人。他的一天是这样:打开电脑,开 TikTok Shop 后台,看数据,改价格,回复客户。他对电脑的理解是"浏览器能上网就是好的"。碰到网络问题,他找 IT;IT 解决不了,他换一台电脑。

你给他看这个:

ghost-proxifier.exe -p chrome -u 127.0.0.1:2080 --watch

他的反应是关掉窗口。不是他不配合,是这个东西设计的时候没把他当人看。

他需要的是:

看到一个进程列表 → 把 Chrome 拖进去 → 看到灯变绿

就这么简单。这个认知负担,差不多等于微信里发一张照片。

做 GUI 这件事,本质上是对用户时间的尊重。你的技术很牛,但用户不应该被迫了解你的技术才能享受你的技术的好处。

为什么是 WebView2?

GUI 框架也挑了半天:

Electron  → 打包 200MB,为一个几 MB 的代理工具塞一个完整的 Chromium。
            就像为了吃一颗糖豆买了一个糖果工厂。

Qt/C++   → 性能好,但 UI 迭代太慢。改一个按钮的颜色要重新编译。
             前端同事没法参与。

WebView2 → Windows 10+ 自带,体积零。
            前端用 HTML/CSS/JS 独立迭代,C++ 核心专注引擎。
            两拨人互不阻塞。

Windows 用户群覆盖率够高,不缺 Electron 的跨平台优势。macOS 版以后再说——那是另一个项目,不是一次移植。


三、"拖入即代理"的进化史

这个交互的设计经历了三次迭代,每一次都是用户反馈在推动:

V1:输入 PID

第一个版本只有一个输入框,用户输入进程 ID,点"注入"。

用户:"PID 是什么?""去哪里找 PID?""Chrome 有好多个进程,输哪个?"

失败。

V2:下拉列表

在 UI 里列出所有运行的进程,下拉选择目标进程。

用户:"Chrome 有 20 个条目,哪个才是真正上网的那个?" "选了 chrome.exe,但开了代理还是不行。"

因为真正上网的是 chrome.exe --type=network-service,不是主进程。列表里全是 chrome.exe,用户根本分不清。

V3:拖拽窗口 + 自动进程树

这就是现在的方案。用户把一个进程拖到代理组区域,系统自动做以下事情:

拖入一个窗口
    │
    ├─ 从窗口句柄 → GetWindowThreadProcessId → PID
    │
    ├─ 展开进程树
    │     CreateToolhelp32Snapshot → 递归枚举所有子进程
    │
    ├─ 逐个子进程 →
    │     判断架构 → 选 SetThreadContext 或 CreateRemoteThread
    │     注入 ghost_core_*.dll
    │     等待 Hook 就绪
    │
    └─ UI 实时反馈:绿色 = 已代理,黄色 = 注入中,红色 = 失败

用户眼中的流程图:

拖进程 → 变绿 → 好了。

从 V1 到 V3,每一次迭代都在问同一个问题:能不能再少一个步骤? 能输入 PID → 能不能不输入 PID → 能不能连选都不用选直接拖?每一个步骤的消除,都是一次转化的提升。

有一个残酷的规律我深信不疑:用户每多做一个动作,就有 30% 的人放弃。 三个多余动作走下来,你的用户已经走了七成。


四、MSI 安装包:第一印象就是产品

很多开源工具在 GitHub 上发一个 zip 就完事——作者觉得"懂的都懂"。问题是,如果你的目标用户不是那批"懂了就懂"的人,zip 就是在赶客。

MSI 安装包做对了这些事:

双击安装       → 不用解压、找 exe、配置环境变量
桌面快捷方式    → 用户第一次打开后能在桌面找到 "下次怎么打开"
开始菜单入口    → Windows 用户的肌肉记忆:"开始 → 搜索 → 打开"
控制面板卸载    → 干净卸载是一个产品的体面
静默安装 /qn   → IT 管理员可以批量部署到公司所有电脑

技术栈:CMake 管构建 → CPack 生成基础 MSI → WiX Toolset 定制快捷方式、安装界面、卸载入口。

这件事没有技术含量。但它决定了用户的第一印象是"像个正经软件"还是"又一个野路子工具"。


五、界面细节里的"理所当然"

几个例子:

右侧栏自动展开

早期版本配置面板常驻右侧,占用一半空间。用户说:"我就是想看进程有没有走代理,为什么半个屏幕都是设置?"改动很小——选择进程后右侧栏才滑出。空间多出 40%。但这个改动之前的版本上线了三个月,我居然从来没觉得它有问题——因为我是开发者,我习惯了。

2 秒的刷新频率

流量监控要实时刷新,但多快是"刚好"?试了 1 秒(UI 抖动,CPU 占用上去)、5 秒(感觉迟钝,用户以为卡了)。2 秒是主观流畅和资源消耗的平衡点。这是一个非常小的数字,但它影响用户的每一次使用体验。

状态灯的三色语义

🟢 绿 = 流量在正常转发 | 🟡 黄 = 等待握手/重连 | 🔴 红 = 代理不可达

这不是原创设计——信号灯在全人类文化里都这么用。但它有效。用户不用看一行文字,余光扫到颜色就知道状态。好设计不是让你思考的,是让你不用思考的。


六、还没做完的

坦诚说出技术债务:

  • 分流规则:现在是"选中进程全部走代理"。下一步是按域名/IP 分流——Google 走代理,内网 IP 直连。Clash 的分流能力,但要工作应用层。
  • 非 Winsock 覆盖:直接 syscall 的程序、用 named pipe 的、raw socket 的——当前方案覆盖不了。Windows 100% 流量拦截最终可能需要 API Hook + WFP 组合。
  • macOS:注入机制完全不同(DYLD_INSERT_LIBRARIES、mach_inject、SIP 限制)。如果做,是一个全新的项目,不是移植。

这些事列出来不是因为焦虑,是因为清楚了边界在哪儿。一个好产品永远不会"做完了"——它只会做到"下一个版本"。


七、六篇回顾

第1篇:网络五层模型           → 看清战场,选择武器
第2篇:Winsock API Hook      → 精确打击,弹性设计
第3篇:注入的艺术             → 借主线程之力,不造新线程
第4篇:进程树追踪             → 从源头拦截,自动传播
第5篇:Cygwin 兼容            → 一个 Bug,三个教训
第6篇:产品化                 → 技术是骨架,产品是血肉

做自己的 Proxifier = 重新理解一遍 Windows 网络栈。从 OSI 模型到 x64 汇编,从 DLL 加载器到 TLS 初始化,从 CreateProcess 到 WiX Toolset——这些知识散落在不同领域,但当你要做一个完整的产品时,它们必须同时出现在你的大脑里。

GitHub: liliBestCoder/ghost-proxifier-pro


讨论:六篇看下来,哪个技术决策最让你意外?如果是你来做,会在哪里选不一样的路?产品上呢——GUI vs CLI、安装方式、交互设计——来评论区聊。