第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、安装方式、交互设计——来评论区聊。