配套阅读:《电商平台中转api为什么便宜?有没有可能是别人手里的三层套娃?》(故事篇)
前置声明:本文全部方法基于本机流量的只读观测——看进程、看端口、看证书库、看本地配置、读客户端自己的日志。不包含任何反编译改造、改包绕过、阻断云端同步、伪造计费身份的操作。这类动作既违法,也拿不回钱;而只读观测已经足够定性。
全文脱敏:域名 →
api.pool.tld/*.vendor.sh;端口 →P1~P4;账号/激活码 →KEY-A/KEY-B;设备号、邮箱、路径中的用户名一律替换。
0. 结论先行
| 待验证命题 | 判定 | 关键证据 |
|---|---|---|
| 客户端接管了本机 HTTPS | ✅ 成立 | 自签根证书入信 + PAC 自动配置 + 进程级 proxy env |
| 接管范围超过它自己 | ✅ 成立 | PAC 只白名单 *.vendor.sh 直连,其余按 hash 匹配;ProxyEnable=0 是障眼法 |
| 存在未告知的第二条信任链 | ✅ 成立 | 根库里两张自签 CA,其一与磁盘 pem 不一致 |
| 套餐/额度是本地伪造的 | ✅ 成立 | 配置里 plan_tier_name / quota_total 被改成固定值 |
| 配置受云端强制覆写 | ✅ 成立 | 约 30s 周期,仅“封装字段”变化,业务字段稳定 |
| 推理强度被强制拉满 | ✅ 成立 | reasoning_effort: "max" 强制覆盖 + 实测 reasoning:content ≈ 9.9:1 |
| “额度耗尽”错误是伪造的 | ✅ 强指示 | 兜底槽位请求 100% 在 <1s 内返回额度错误,与真实上游耗时分布不重叠 |
| 计费核对在远端 | ✅ 成立 | 客户端空闲时 asks 不变而池余额下降(云端同步滞后) |
1. 起点:这个端口是什么
故事从一句很朴素的问题开始:127.0.0.1:<P> 是什么?
只读三步:
# 1) 谁在监听
Get-NetTCPConnection -State Listen |
Where-Object { $_.LocalPort -in <P1>,<P2>,<P3>,<P4> } |
Select-Object LocalAddress,LocalPort,OwningProcess | Format-Table
# 2) 进程是不是一个被冻结的 Python 程序
Get-CimInstance Win32_Process |
Where-Object { $_.Name -match 'client|launcher' } |
Select-Object ProcessId,Name,CommandLine | Format-List
# 3) 代理是怎么进入环境的
'HTTP_PROXY = ' + $env:HTTP_PROXY
'HTTPS_PROXY = ' + $env:HTTPS_PROXY
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable,ProxyServer,AutoConfigURL | Format-List结果(脱敏):
LocalPort OwningProcess
P1 PID_launcher ← 控制面 API
P2 PID_proxy ← 流量统计
P3 PID_proxy ← mitm 代理本身
CommandLine : ...\dist_xxx\client.exe --proxy-mode --quiet
--stop-file ...\.proxy_stop --launcher-pid PID_launcher
HTTP_PROXY = http://127.0.0.1:P3
ProxyEnable = 0 ← 关键:看着是关的
AutoConfigURL = http://127.0.0.1:P3/proxy.pac ← 实际是 PAC 在生效第一个认知纠正:很多人看“系统代理”显示关闭,就以为网络是干净的。真正生效的是 PAC 自动配置。ProxyEnable=0 只影响“手动代理”,对 AutoConfigURL 无效。而所有走 WinINET/WPAD 的程序(浏览器、Electron 全家、系统更新)都会读 PAC。
这条也解释了为什么它要同时用两种注入方式:env 变量管不读 PAC 的程序(CLI/Node),PAC 管读 PAC 的程序。双保险。
2. PAC 里的隐藏域名:一个 DJB2 hash
PAC 文件本身不复杂,但有一段值得单独看:
// 原文件:SALT 为 "<产品名>.pac.v1|",此处以占位符 SALT 代替
var _p = host.split("."), _i, _j, _s, _h;
for (_i = 0; _i < _p.length; _i++) {
_s = SALT + _p.slice(_i).join(".");
_h = 5381;
for (_j = 0; _j < _s.length; _j++) {
_h = ((_h * 33) ^ _s.charCodeAt(_j)) >>> 0;
}
if (_h == <常量>) { return "PROXY 127.0.0.1:P3"; }
}
return "DIRECT";这是经典的 DJB2(hash = hash*33 ^ c),对 host 的每一级后缀做一次。它把要拦截的域名藏成了一个无意义的整数常量。
反解很简单——枚举后缀,算 hash,比对:
SALT = "<产品名>.pac.v1|" # 从 PAC 原文抄出
TARGET = <常量> # 从 PAC 原文抄出
def djb2(s):
h = 5381
for ch in s:
h = ((h * 33) ^ ord(ch)) & 0xFFFFFFFF
return h
for host in ["api.pool.tld", "pool.tld", "*.vendor.sh", ...]:
parts = host.split(".")
for i in range(len(parts)):
suf = ".".join(parts[i:])
if djb2(SALT + suf) == TARGET:
print("MATCH ->", suf)结果命中:它自己的三方池域名(此处记作 api.pool.tld)。
这意味着什么? 它连自己的上游都要 MITM 一遍。如果只是转发,不需要解密自己到上游的 TLS。要解密,就说明中间有一层可以读、可以改的环节——而这正好对应“降智”“注入”“改写请求体”这类操作的落点。
附带结论:这份 PAC 写的白名单是“官方域名直连”。也就是说,除了官方域名,其余它想拦的都会拦。白名单制的反向用法,是“精确劫持”。
3. 证书审计:两张自签,一张没告诉过你
为什么要盯这一项?
单套 mitmproxy 只需要一张 CA。多出来的那张意味着第二条信任链,有效期同样到 2036 年。技术上,你无法区分它是“历史遗留”还是“另一套工具的入口”;但从审计角度,任何你未被明确告知的根证书,都应视为高优先级风险——一张被信任的根证书,等价于“可以无提示地解密你所有 HTTPS”。
合法软件(企业 SSL 检查、杀软、代理工具)装根证书本身不违法,但必须明示。没有明示的,就是问题。
4. 配置:它是怎么“伪造”额度的
客户端把自己的运行时配置落成一个明文 JSON(记作 rewrite_config.json)。
三个洞察:
① “额度”是本地字段,不是服务端账本。quota_total: 10000000 和 plan_tier_name: "Premium" 是写死的字符串。它让面板显示成“你是尊贵用户,还有一千万额度”。这个数字与你实际被扣多少毫无关系——真实扣减发生在远端,本地这个只是个 UI 假象。
② reasoning_effort: "max" 是全局强制。
注意它不只是“默认值”,而是 parameters_override:不管你请求里写什么,都会被覆盖成 max。再叠加兜底槽位 * 的 xhigh,等于任何未命中槽位的模型,都会跑最高推理强度。
③ 槽位与“官方/三方”的分流。auto/performance 指向 ide_38(efficient 也是),而 ultimate/cmodel 指向掩码上游 ID。这两条腿的成本结构完全不同——下一篇会证明 ide_38 其实走的是官方端点。
4.1 配置会被云端覆写
每隔约 30 秒,配置文件的部分字段会被重写。实测特征:
- 只有“封装块”(几个 base64/加密的 blob)与
updated_at变化; - 业务字段(
e_router.models的映射、chat_rewrite参数)稳定不变; - 你在本地改的参数,下一个周期就被打回。
结论:你无法在本地夺回计费控制权。这也从侧面证明——它知道你在改,并且不允许。
我没有尝试阻断这个同步。那属于“绕过服务端控制”,既不合法,也不必要:观测本身已经给出结论。
5. 量化:钱到底花在哪
5.1 只看两个数:content_chars 与 reason_chars
代理自己暴露了一个统计端点(只读 GET),由此算出三个指标:
| 指标 | 计算 | 实测 |
|---|---|---|
| 推理/产出比 | reason_chars / content_chars | 6.9 ~ 9.9 : 1 |
| 单次流式分片数 | frames / asks | ≈ 370 片/次 |
| 单次平均上游耗时 | upstream_ms / asks | ≈ 22 ~ 24 s |
这三条一起看,就把“高级模型”的话术拆了:
- 推理比 9.9:1 → 你付费的 token 里,约 90% 是你看不到的“思考”;
- 370 片/次 → 输出被切得很碎,流式“看起来在动”,但信息密度低;
- 22~24 秒/次 → 它不快,它很慢。
对应故事篇那句:“降不降智是模型的问题,烧不烧钱是参数的问题。”reasoning_effort从low拉到max,消耗量级差异通常是 数倍;这与“300 Credits 从三天变三小时”完全吻合。
5.2 两条腿的流量分流
从本地日志统计 API 路径分布(只读 grep 日志文件,注意排除自己写进日志的文本污染):
| 路径 | 出现次数 | 归属 |
|---|---|---|
/algo/api/v1/ping | 998 | 心跳 |
/algo/api/v2/service/pro/sse/agent_chat_generation | 698 | 真正的对话请求 |
/algo/api/v5/service/region/endpoints | 54 | 区域端点发现 |
/algo/api/v2/service/business/finish | 48 | 结算上报 |
/algo/api/v2/byok/config | 2 | 自带 Key 通路(存在) |
关键点:对话请求打的是官方路径。而 e_router 的三方池 base_url 是另一条(http://api.pool.tld:PORT/v1)。
于是得到拓扑:

- 一条腿去官方
*.vendor.sh(走 PAC 白名单直连,但仍被 MITM 解密后转发); - 一条腿去三方池
api.pool.tld(被 PAC 精确劫持 + 自己 MITM 自己)。
两套计费同时在跑:池里的预付额度在掉,官方额度也没省下。
6. 决定性证据:ide_38 到底是不是“免费通道”
一个很自然的省钱假设是:把模型切到兜底槽位 ide_38,既然它不走三方池,是不是就不花钱?
验证方法:把两个独立数据源按时间戳对齐——
- 源 A(IDE 侧):会话事件日志里的
model.request.started,含{ts, model}; - 源 B(官方侧):
qodercli.log里的错误行,含ts与错误文案。
实测(一小时内),然后做时间配对(兜底请求 → 1 秒内的官方错误):
| # | 请求时间(lmodel) | 官方错误时间 | Δ | 配对 |
|---|---|---|---|---|
| 1 | 22:02:14.531 | 22:02:15.214 | +683ms | ✔ |
| 2 | 22:05:41.208 | 22:05:41.872 | +664ms | ✔ |
| … | … | … | … | … |
| 12 | … | … | +5xx ms | ✔ |
12/12 全部配对,Δ 落在 513~683ms。 而正常上游耗时是 22~24 秒。两个分布完全不重叠。
结论(推翻我先前的判断):
ide_38不是免费通道。它把请求转发到官方端点https://api3.vendor.sh/algo/api/v2/service/pro/sse/agent_chat_generation,官方在 0.5 秒内 就返回“额度耗尽”类错误。也就是说:切到
ide_38不是省钱,是直接不可用。 而且我此前提过“切到 efficient → 池消耗为零”,这个结论是错的,在此撤回。
同时它解释了供应商公告里那句“降智时会提前报积分异常”——这个“积分异常”不是官方真实状态,而是被制造出来的假错误,用来把“用不了”解释成“你的额度问题”。
6.1 一个反常现象:asks 不动,池却在掉
连续采样两个端点(均为只读 GET):
s = GET http://127.0.0.1:P2/ # {"stats": {"asks", "frames", ...}}
q = GET http://127.0.0.1:P1/api/state # {"pool": {"total_remaining", "keys": [...]}}两分钟空闲采样:
00:14:55 asks=341 frames=132123 pool=398.71
00:15:15 asks+0 frames+0 pool -1.53
00:15:36 asks+0 frames+0 pool +0.00
00:15:57 asks+0 frames+0 pool +0.00
00:16:18 asks+0 frames+0 pool +0.00
00:16:38 asks+0 frames+0 pool +0.00
00:16:59 asks+1 frames+0 pool +0.00解读:
asks不增,池仍可能下降(-1.53)→ 扣减不是“每请求实时记账”,而是云端周期性对账,且存在滞后;- 池余额的权威源在服务端,本地面板只是缓存;
- 因此“看着还有额度”与“实际可用”可能不一致——这正是“突然登不上”的机制之一。
同时注意 asks 的绝对值和 IDE 侧请求数对不上(asks=335 vs IDE 侧 240)。说明 stats.asks 计的是代理转发单元(含重试、探活、非 IDE 流量),不能直接当“对话次数”用。做相关性分析必须用两个独立源交叉验证,不能只看一个数字。
7. 复现清单(只读、可自查)
如果你想自己验证,你可以让AI按这个顺序去跑,全程不做任何修改:
# ① 谁接管了网络
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable,AutoConfigURL,ProxyServer
$env:HTTP_PROXY; $env:HTTPS_PROXY; $env:ALL_PROXY
# ② PAC 内容(看白名单 + 常量)
Invoke-WebRequest "$env:HTTP_PROXY/proxy.pac" -UseBasicParsing | Select-Object -Expand Content
# ③ 你信任了谁
Get-ChildItem Cert:\CurrentUser\Root | Where-Object { $_.Subject -match 'mitm|proxy' } |
Select-Object Subject,Thumbprint,NotAfter
# ④ 谁在监听、谁在跑
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in <你的端口> }
Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -match 'proxy-mode' }
# ⑤ 客户端自己的统计(只读 GET)
Invoke-RestMethod "http://127.0.0.1:<统计端口>/"
Invoke-RestMethod "http://127.0.0.1:<控制端口>/api/state"判读标准:
| 现象 | 含义 |
|---|---|
AutoConfigURL 指向本地端口,但 ProxyEnable=0 | 用 PAC 隐蔽接管,不是常规代理 |
| 根库里有多张未告知的自签 CA | 可无提示解密你全部 HTTPS |
配置里有 quota_total / plan_tier_name 固定值 | 套餐是展示层伪造 |
reasoning_effort 被 parameters_override 覆盖 | 推理强度不受你控制,直接放大成本 |
| 配置文件按固定周期被重写 | 云端强制覆写,本地无法夺回控制 |
| 兜底槽位请求 <1s 返回额度错误,且与真实耗时分布不重叠 | 该路由不可用,错误是伪造的 |
8. 我不做什么,以及为什么
以下四件事我都不会做,也不建议任何人做:
| 不做 | 理由 |
|---|---|
| 阻断云端配置同步 | 属于绕过服务端控制,且不解决“号池不可用”的根本问题 |
| 反编译/篡改客户端 | 可能触碰著作权与计算机信息系统相关法律风险 |
| 抓包改包绕过计费 | 直接构成规避付费,民事上必输,刑事上有边界风险 |
| 继续消耗它的池、或把改造版分发 | 前者扩大损失,后者是二次违法 |
只读观测的价值在于:它给你投诉、退款、曝光所需的事实,而不给你制造新的法律责任。
9. 附:一个可复用的“中转站尽调”检查表
下次评估任何中转/转售客户端,按这 6 条打分:
- 模型身份可验证吗? 能否拿到可复核的上游模型 ID?(掩码 ID ≠ 可验证)
- 计费可对账吗? 能否导出逐请求的 token/费用明细?(只有“面板余额”=不可对账)
- 推理强度可控吗? 请求参数会不会被强制覆盖?
- 装了什么到你机器上? 根证书、PAC、系统代理、后台进程——有没有明示?
- 本地配置稳定吗? 会不会被远端周期覆写?
- 出问题的解释是“可证伪”的吗? “风控/高级模型/排队”这类词,本质是不可证伪的免责话术。
第 6 条是总闸:一个不愿意让你验证的卖家,前 5 条答得再漂亮也没有意义。
10. 小结
- 它劫持的是整机,不止 IDE:PAC 精确劫持 + 双通道注入 + 未告知根证书。
- 它伪造的是“你的身份”:
Premium/quota_total写在本地文件里。 - 它放大的是你的成本:
reasoning_effort拉到 max,推理/产出 ≈ 9.9:1。 - 它藏的是一条腿:兜底路由指向官方端点,12/12 在 0.5 秒内失败——“免费通道”不存在。
- 它真正收费的是你的时间:排队、切号、排查,全部不开发票。
数据不会安慰你,也不会骗你。
你唯一需要确认的,是它愿不愿意让你看。
本文仅记录对本机流量与本地文件的只读观测,未进行任何破解、改包、绕过计费或阻断服务的操作。所有厂商标识、域名、端口、账号信息均已脱敏,结论不针对任何特定主体,仅供技术讨论与消费者风险提示。