只用 Node 内置模块(node:sqlite / node:http / node:crypto),不需要 npm install。
短信验证码登录 / 密码登录 / 粘贴 cookie —— 效果完全一致。
costTime、画笔算法(弧线 / 七段码)、轮间隔、答题间隔、频控退避。
基于 AbortController 的真中断:在途请求与等待都能秒断,不用等本轮跑完。
任务之间可并行(默认上限 3),每个任务内部仍逐轮串行。
SSE 推送每轮进度,带事件回放与轮询兜底,刷新页面不丢历史。
要求 Node.js >= 22(用到内置 node:sqlite)。除此之外零依赖,
不需要 WSL / Docker / qemu,也不需要任何 arm64 原生库。
方式一:下载免安装包(推荐)
# 从 Releases 下载 zip,解压后:
# Windows:双击 start.bat
# Linux / macOS:./start.sh
方式二:从源码运行
git clone https://github.com/sxd91/pk-node.git
cd pk-node
./start.sh # 默认 http://127.0.0.1:8787(被占用会自动往后找)
# Windows:start.bat
浏览器打开 → 用 admin / admin 登录 → 第一次登录后请立刻改密。
node bin/selftest.js
# 检查:编码链路 / sign 公式 / RSA 编码 / 笔画算法 / 提交体结构 / 模块导出
原本两个关键环节是 arm64 原生实现,现在都已解除依赖,纯 JS 即可:
| 环节 | 说明 |
|---|---|
内容编码器 |
已拆解为「固定密钥流 XOR」,纯 JS 实现。差分分析证明 c() 就是逐位置异或一条固定密钥流(128 KiB,bin/keystream.bin),在 1B~128KiB 各长度上逐字节等于原生结果,且与真机抓包密文一致。耗时 80–250ms → ~14ms。 |
sign |
PK 端点实测不需要,已默认关闭。不带 sign 时 match 与 submit 都返回 200;带 sign 反而遇到过 403。需要时设 PK_SIGN_MODE=on。 |
| 内容编码器 | 已用纯 JS 复现,不再需要原生库。差分分析证明 c() 就是「与固定密钥流逐位置 XOR」(翻转 1 bit 只变同位置 1 字节、in XOR out 的流恒定、与总长无关、确定性),因此编码全零即得密钥流。纯 JS XOR 在 1B~128KiB 各长度逐字节等于原生结果,且与真机密文一致;耗时从 80–250ms 降到 ~14ms。 |
在 proot 里跑 Android so 的方式:
LD_LIBRARY_PATH=bin/native bin/native/linker64 bin/native/enc_device <so> <in> <out>
| 项 | 说明 |
|---|---|
| 子账号切换 | 做不到。服务端切号接口对非 App 客户端一律 417;而 userid cookie 被服务端忽略(改本地 cookie 无效,已实测)。身份由服务端会话绑定 —— 如需换号,请在原版 App 里切好再重新导入 cookie。 |
| 平台限制 | 已无 arm64 依赖:内容编码是纯 JS,sign 默认关闭。Windows / x86_64 可以完整刷局,不需要 WSL 或 qemu。bin/native/ 可整个删掉。 |
| 频控 | 出题与提交接口都有服务端频控。刷太快会 403 / 400「请求过于频繁」,这是正常保护,不是 bug。 |
| 风控头 | x-shepherd-did 需自己从本机取(见 README)。留空则不发送。 |
| cookie 存储 | 小猿 cookie 以明文存在本地 SQLite。谁能读到那个文件谁就能拿到登录态 —— 默认只监听回环,且已被 .gitignore 排除。 |
| 第三方二进制 | bin/native/ 下的系统库与 App 库不属于本项目,不在 MIT 授权范围内,见 NOTICE。 |
pk-node/
├── server.js # HTTP 服务 + 路由(零依赖)
├── start.sh / start.bat # Linux / Windows 启动脚本
├── src/
│ ├── config.js # 配置与协议常量
│ ├── db.js # SQLite 层(node:sqlite)
│ ├── http.js # HTTP 客户端 + CookieJar(可中断)
│ ├── crypto-rsa.js # RSA 编码(手机号 / 验证码 / 密码)
│ ├── sign.js # sign 公式(纯 JS 复现的 4 轮 MD5 链)
│ ├── keystream.js # 内容编码器(纯 JS:固定密钥流 XOR)
│ ├── native.js # 编码链路封装 + sign 按 PK_SIGN_MODE 开关
│ ├── strokes.js # 画笔算法:弧线 / 七段码
│ ├── leo.js # 小猿协议层
│ ├── pk-engine.js # 出题 → 组 body → 加密 → 提交
│ ├── jobs.js # 任务调度(并行 / 立即结束 / SSE 缓冲)
│ ├── tunnel.js # Cloudflare 快速隧道
│ └── services/ # auth / login / leo-accounts
├── public/ # 网页(原生 HTML+JS+CSS,无构建)
├── bin/
│ ├── keystream.bin # 密钥流(128 KiB,内容编码器必需)
│ ├── selftest.js # 命令行自检
│ └── pick-port.js # 端口避让
├── tools/
│ ├── make-release.js # 打免安装包
│ └── keystream-extract.js # so 换版本时重提密钥流
└── .github/workflows/ # CI:自检 + 启动冒烟 + 打 tag 出 Release
本项目仅供学习与技术交流使用。严禁用于商业用途、批量刷分、代练或任何违反服务条款与法律法规的行为; 使用者自行承担全部风险与责任。本项目与「小猿口算」及其运营方无任何关联。 若权利人认为内容侵权,请通过 Issues 告知,核实后立即删除。 详见 DISCLAIMER.md。