配套阅读:《电商平台中转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_chars6.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/ping998心跳
/algo/api/v2/service/pro/sse/agent_chat_generation698真正的对话请求
/algo/api/v5/service/region/endpoints54区域端点发现
/algo/api/v2/service/business/finish48结算上报
/algo/api/v2/byok/config2自带 Key 通路(存在)

关键点:对话请求打的是官方路径。而 e_router 的三方池 base_url 是另一条(http://api.pool.tld:PORT/v1)。

于是得到拓扑:

AI 中转客户端的新套路:在不破解的前提下,如何证明它连伪造“额度”都“偷”.jpeg

  • 一条腿去官方 *.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)官方错误时间Δ配对
122:02:14.53122:02:15.214+683ms✔
222:05:41.20822: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 条打分:

  1. 模型身份可验证吗? 能否拿到可复核的上游模型 ID?(掩码 ID ≠ 可验证)
  2. 计费可对账吗? 能否导出逐请求的 token/费用明细?(只有“面板余额”=不可对账)
  3. 推理强度可控吗? 请求参数会不会被强制覆盖?
  4. 装了什么到你机器上? 根证书、PAC、系统代理、后台进程——有没有明示?
  5. 本地配置稳定吗? 会不会被远端周期覆写?
  6. 出问题的解释是“可证伪”的吗? “风控/高级模型/排队”这类词,本质是不可证伪的免责话术。

第 6 条是总闸:一个不愿意让你验证的卖家,前 5 条答得再漂亮也没有意义。


10. 小结

  • 它劫持的是整机,不止 IDE:PAC 精确劫持 + 双通道注入 + 未告知根证书。
  • 它伪造的是“你的身份”:Premium / quota_total 写在本地文件里。
  • 它放大的是你的成本:reasoning_effort 拉到 max,推理/产出 ≈ 9.9:1。
  • 它藏的是一条腿:兜底路由指向官方端点,12/12 在 0.5 秒内失败——“免费通道”不存在。
  • 它真正收费的是你的时间:排队、切号、排查,全部不开发票。
数据不会安慰你,也不会骗你。
你唯一需要确认的,是它愿不愿意让你看。

本文仅记录对本机流量与本地文件的只读观测,未进行任何破解、改包、绕过计费或阻断服务的操作。所有厂商标识、域名、端口、账号信息均已脱敏,结论不针对任何特定主体,仅供技术讨论与消费者风险提示。