• task.hexdo.com 探测发现指向错了 Mac 的 agent-bridge,域名重新分配后
    (详见 docs/2026-08-07-task-hexdo-tunnel-and-wechat-watcher.md),把
    task.hexdo.com 隧道健康检查/自愈加进看门狗第 7 节;顺带修复微信自动
    回复 watcher 的判活逻辑(`ps -A|grep` 在设备负载下不可靠导致健康进
    程被误判重启),改用 pidfile + /proc/cmdline 判活,并修掉 log() 把
    每行日志写两遍的小 bug。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • 验证了当前真机 Tinker 补丁(patch-83069b25,2026-07-12,含 libapp.so
    确认贴图号 Flutter 功能是热更新下发的)里的 BizPublishApi/lx.m5 跟
    base.apk 反编译内容完全一致,排除"反编译资产过期"这个猜测。
    
    用 jadx 读了 BizPublishApi$Companion.setUp() 完整分发逻辑:11 个
    Pigeon BasicMessageChannel 直接调用对应方法,无代理/反射,hook 位置
    技术上完全正确。两轮真机验证零触发的唯一合理解释:Dart 侧压根没为
    "贴图号+单图+短文字"这个简化流程发送这条消息——这套 Pigeon 桥接更
    可能服务于另一个更复杂的发布场景(完整公众号图文),跟当前测的路径
    无关,这条线大概率是死胡同。
    
    记录了三个待选的下一步方向(精确时间线比对 js1.m.c() 洪流 / hook
    WCDB 写库回溯调用栈 / 接受半自动方案),留待下次接手。
    yibo authored
     
    Browse Code »

  • 用户提议直接读源码而非继续 hook 排除法,引出两条新调查线:
    
    1. 小程序运行时 JS 缓存(jscache 目录,非加密 wxapkg,已解出但是微信
       自己的编译字节码)——strings 扫出完整模块树,确认 utils/massSend/
       massSend.js 是实际提交逻辑所在,但字节码格式读不出具体调用参数。
    
    2. 按"类名含 Publish"批量搜索,发现 com.tencent.pigeon.biz.BizPublishApi
       ——Pigeon 是 Flutter 官方 native↔Dart 桥接代码生成器,证实"我的作品"
       入口(BizMyWorksFlutterViewActivity)是真 Flutter 页面,跟原生通信
       走一条完全独立于此前四条候选的 IPC 机制,解释了为什么 js1.m/m11.l0/
       wxartrappsvr/v70.w 全部落空。
    
    找到实现类 Llx/m5,hook 了 notifyBizPublishResult()/openUrl()(含新观察
    到的独立进程 com.tencent.mm:hotpot..,疑似"我的作品"专用 Flutter
    隔离进程)。两轮真机验证:hook 全部安装成功,但零触发,发布依旧真实
    成功。这是今天第二次"反编译读到的类看起来对,装上却零触发"(第一次是
    JsApiOpenBizPublishImage 主类被 R8 优化到连文件都找不到)。
    
    关键教训:~/wechat_apk/decompiled 是历史某个时间点的 dump,可能已经
    跟当前真机在跑的版本对不上(Kotlin/R8 生成的短类名对小版本更新敏感)。
    下次要精确 hook 前应重新 dump 当前 base.apk,而不是复用旧反编译资产。
    yibo authored
     
    Browse Code »

  • 加了 hookGenericImgCdnSubmit 被动观察 v70.w.oj()(普通消息发图真正
    CDN 上传入口,已在 wechat-image-send-internals.md 逆向过),测试贴图号
    提交是否复用这条通道。真机确认:全程零触发,发布依旧真实成功
    (chksm 变化),第四个假说证伪。
    
    至此 js1.m.c()/bizh5webtransfer、m11.l0.d1()、wxartrappsvr/route、
    v70.w.oj() 四条最合理候选全部用真机数据排除。hookAnyCgiCapture 已是
    全局通用观察点,纯靠猜类名排除法收益递减,建议下次改查小程序沙箱
    自身 JS bridge 层(wx.uploadFile/wx.request 的 native 实现,appbrand
    包下,全新方向)。
    
    顺带记录一个流程坑:设备中途自己息屏落锁,wm dismiss-keyguard 对有
    密码锁的设备无效,需要用户物理解锁,不能也不该尝试绕过。
    yibo authored
     
    Browse Code »
  • 改用 adb input tap + screencap 自主驱动"我的作品→贴图号→发表"全流程,
    不再需要用户手动操作,缩短每轮迭代成本。真机验证坑:可折叠机
    screencap 默认拿错屏幕,需显式 -d <display-id>。
    
    给 hookAnyCgiCapture 加了 r45.zt5(wxartrappsvr/route)专属 dump——
    之前通用扁平字段扫描器看不到它的 LinkedList<re7> payload,误判成
    "无内容"。真机确认这条路全是小程序 SDK 埋点上报(页面性能/console log
    转发/事件上报),跟提交发布无关,第三个候选证伪。
    
    意外发现:图片编辑步骤本身是个独立小程序(appid wx0b2ec076ec39c786,
    page_path pages/image_editor/image_editor),此前一直当作纯 H5
    webview——这是下次调查该跟进的新方向。核心提交调用仍未定位。
    yibo authored
     
    Browse Code »
  • 改用文字/图片/语音发送同一套 LSPosed 机制(Zygote fork 时挂钩,非 Frida
    spawn/attach),彻底避开了此前两次搞坏微信主进程的问题——全程真机验证零
    故障。
    
    追踪链路 js1.m.c()(brandservice/webview transfer 汇聚点) → wire cgi
    bizh5webtransfer,真机确认全程只有只读态 mp.weixin.qq.com 调用,没有
    提交语义。进一步反编译 LuggageUploadMediaFileManager 追出图片走独立 CDN
    服务 m11.l0.d1(),同样零触发。两个最有希望的候选均被真机数据证伪,真正
    的提交调用点仍未定位,可能是完全独立的第三条路径。
    
    三个新增 hook(hookBrandservicePublishTransfer/hookAnyCgiCapture/
    hookBrandserviceCdnUpload)均已装进 WeChatHook.java,base+Tinker CL
    全覆盖,可复用于下一轮排查。
    yibo authored
     
    Browse Code »
  • 第二次尝试(spawn 后立即 resume,隔 0.8s 再 attach)连 hook 都没装成功
    (frida 自身 JVMTI attach 报 access violation),但微信依然被搞挂(这次
    表现为界面卡死而非"无法连接服务器")。两次事故一次 hook 装成功一次没装成功,
    排除了"hook 代码本身有 bug",说明是"往微信主进程冷启动过程里做 frida
    attach"这个动作本身在这台设备这个微信版本上就不安全,不是时序调参能解决的。
    
    建议:不再对主进程做任何 frida spawn/attach 变体;appbrand 子进程的
    spawn-gating hook 依然安全可复用;退回半自动方案(人工点发布)性价比
    明显更高。
    yibo authored
     
    Browse Code »
  • 多轮真机验证过程:
    - frida -W 三开会撞车崩溃目标进程(一次只开一个)
    - frida -W 只逮第一个匹配 spawn,改写 multi_spawn_hook.py 用
      enable_spawn_gating()+on('spawn-added') 逐个处理
    - session.create_script() 原生 Python binding 不像 CLI 自动 bundle
      frida-java-bridge,需 frida-compile 预编译(*_bundled.js)
    - 反编译代码确认 k2/y7(小程序侧)和 webview/luggage/jsapi(WebView 侧)
      都汇聚到同一个 sink:Ljs1/m;->c(TransferRequestInfo, callback),大概率
      跑在微信主进程而非 appbrand 子进程
    - spawn_mm_and_hook.py 尝试 force-stop+spawn 主进程挂钩子,导致微信"无法
      连接服务器",force-stop 后手动重开恢复正常——确认主进程冷启动期间注入
      有风险,不同于此前 appbrand 子进程的安全操作
    
    详细过程记录见 BRANDSERVICE_PUBLISH_RESEARCH.md §3。
    yibo authored
     
    Browse Code »
  • MITM 网络层拦截确认死路(贴图号走 MMTLS,跟 IM 消息一样不可读),
    改从 LiteAppJsApiExtTransfer/WebTransfer 的 k2.a()/y7.a() hook 拿明文
    reqUrl/reqBody,绕开 MMTLS。hook 脚本验证过能跑,Frida attach 存量
    appbrand 进程会超时,只有 -W 等全新 spawn 能抓到。
    
    mitm_proxy.py 顺手加了本地 jsonl 抓包日志(调试用,跟本次逆向工作
    共用同一台设备)。
    yibo authored
     
    Browse Code »


  • discover_accounts() 对 MicroMsg/ 下全部 56 个子目录逐个发 su -c test -f,
    但只有 18 个是 32 位十六进制的真实账号目录,其余是微信自己的缓存/功能目录
    (CronetCache/emoji/jscache/hpRevert/...)。这段逻辑在模块导入时跑一次,
    即 Flask app.py 每次启动/重启都重新扫一遍,白白多发 38 次 su 进程。
    
    改为先按目录名过滤(^[0-9a-f]{32}$)再探测。真机验证:账号发现结果不变
    (仍正确识别当前登录账号 653cdc2320abb089e149a3f7a7683fcf),单账号池
    1.11s 内完成。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • 手机后台卡死到连电源键都无响应:wechat_reply_watcher.py 死循环+
    wechat-viewer-watchdog.sh(Hermes cron 每 5 分钟跑一次)检测存活只信
    一次 su -c 'ps -A'|grep,系统过载时该探测本身会漏检,导致在卡死的旧
    实例上不断叠加新实例,6 天内滚雪球到 877 个同时存活进程,吃满内存
    +swap 拖死整机。
    
    修复:watchdog 第 5 步改为每次都先 pkill 清场再起一个(与同文件里
    Flask 重启逻辑一致的幂等单例模式),不再依赖探测结果是否可靠。已在
    设备上部署验证。
    
    顺带把 wechat_reply_watcher.py / orchestrator.py / policy.py 同步为
    设备上过去两周的最新版本(repo 里是旧的,device 端已经跑在更新版本
    上——非 root Termux su fallback、admin/member 双角色回复、去重、独
    立验证层等),此前只有 daemon.sh 和 service.d 脚本是同步的。
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • - 修复 BOSS直聘登录被安全检测拦:根因是 wechat_plain 的全局设备型号伪装
      脚本连累风控,禁用脚本恢复真实机型后登录正常
    - 本地库明文无加密,Contact/MessageTable 结构与持久化触发时机(反编译确认)
    - parse_resumes.py: 简历(ChatResumeBean)+职位卡片(ChatJobBean)反序列化导出,
      支持招聘模式(myRole=1)/牛人模式(myRole=0)双角色
    - scan_geek_list.py: 纯读屏方案(uiautomator dump + swipe)记录候选人列表,
      不调用私有接口
    - README 第四节写死三条边界:不做自动沟通/自动回复、不做私有接口批量抓取,
      搬到 Hermes 上跑也不改变判断
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • - 取自设备 ~/wechat-viewer 工作目录(含未提交改动),比其自身 GitLab(pixelfiles) 新
    - 只带源码:排除 *.db/*.log/static 头像图/__pycache__ 等数据与运行产物
    - 保留 .wechat_key_* 等密钥(本仓库 push 到自建私有 GitLab)
    - CLAUDE.md: 子项目表 + 新增 §wechat-viewer 定位说明(Hermes 侧,非 lifelog 脉络)
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • 红点通知需 atuserlist,深逆向未到底,跟原生引用气泡一起后面做。已确认:
    - 纯文字@不触发红点;atuserlist 不在 message 行(convertTo cv 无此列)
    - r0 第5参 obj≠msgSource(当它传会 NPE g9.q5,obj 是"消息key查f9")
    - 微信 UI 发送链路≠我们合成的 r0+z2.b:hook z2 自学习扫 atuserlist 字段零命中
    
    已部署脚手架(WIP,生产不传 at 无影响,自动回复照常):
    - SEND_MSG_INTERNAL 支持 --es at → 构造 msgsource
    - trySendWithRetry/sendViaHighLevel 加 msgSource 参数
    - hookAtDiscovery 自学习 z2 派发点 + sAtFieldPath 持久化(目前学不到)
    
    详见 memory wechat-group-at-atuserlist。⚠️ 重编译 hook 会强退微信=要重登,
    继续挖前一次想全要抓什么。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • - process_event 里确定性拼接 @昵称+U+2005(微信原生分隔符)前缀,仅群消息(isGroup)
    - 确定性代码不靠 LLM/skill(否则会漏会不一致);安全判定仍在原始 draft 上跑
    - 审批页/自动发的文本都带 @;送达校验用带 @ 的文本匹配
    - ⚠️ 仅文字@(可见),不带 atuserlist,未必真 ping 红点;真通知需 hook 加 at 列表(README 待收尾)
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • - 需求文档环节5:补 flush 加固三经验值 + 端到端闭环验证(私聊+群@我送达)
    - README 真机验证:加 2026-07-12 里程碑段(系统正式跑通,~15s 送达)
    - .gitignore 忽略 __pycache__/*.pyc
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • 用户实测发现:触发 NetSceneQueue 派发的是一次真实 app 切换(切走→切回微信),
    且要给足时间。旧版单次切换+被动等 25s 常卡几十秒~分钟。三个经验值:
    - 发送后 sleep(4) 让消息稳稳落库(切太快微信还没登记这条,flush 不到)
    - _onresume_cycle: HOME 背景化 2.5s → am start LauncherUI 切回停 3s(切换给足时间)
    - 切回后停前台连查 DWELL_POLLS 轮,不立刻再切走(否则打断正在进行的网络发送);
      没到 2 再来一轮,总超时 60s
    
    真机实测:屏幕亮/灭(Dozing)都 ~15s flush 到 status=2。memory
    wechat-api-send-onresume-flush 已补加固经验。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • - app.py 加 GET/POST /api/auto_send:读写 policy_config.json 的
      auto_send_enabled(root 属主 644,写经 tmp+su cp,只翻该字段保留 block_keywords)
    - whitelist.html 顶部加开关卡片(开=白名单自动发/敏感词仍拦,关=全审批),开启二次确认
    - orchestrator 每轮 load_config() 即时生效,无需重启
    - 真机验证:读接口 enabled=false、POST true/false 文件正确翻转其余字段完整、/whitelist 200
    - README 待收尾 #4 标完成
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • 复盘 2026-07-11 从"以为一个 hook 就完事"到"挖了四层才根治"的完整过程:
    Java Build.* / native __system_property_get / 系统 settings device_name /
    微信自己首装存下的持久 MMKV 缓存(mmkv.default),缺一漏一处。
    含无效弯路(Settings hook/分区 prop hook 零命中)、正确解(resetprop+
    settings put+清 mmkv 缓存)、按账号不同现象的服务器端记录解释、维护坑。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • 微信在 native __system_property_get 读 ro.product.model,绕过所有 Xposed
    Java hook,登录记录显示真机 "Pixel 10 Pro Fold" 触发预警。
    
    - hookDeviceSpoof: SystemProperties.get 改模式匹配 ro.product.*.model
      + hook Settings.{Global,Secure,System}.getString(device_name/bluetooth_name)
      + hook BluetoothAdapter.getName() + 诊断日志(定位真实读取源用)
      → 真机验证这些 Java hook 全零命中,证实微信走 native 读
    - 真正生效: wechat-model-spoof.sh 用 Magisk resetprop 改系统属性层
      (装到 /data/adb/post-fs-data.d/,开机持久化),native 读也拿伪装值
      → 登录记录变 "samsung SM-X700",Pixel 泄露消失
    - 代价:全机生效(getprop 也变),放弃"仅微信进程内",native 读无法 per-app
    
    详见 memory wechat-pad-login-device-spoof。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • - text_b64 传中文(--es text 被 shell/am 弄乱→卡 status=1)
    - z2.b 只入队,发送后 HOME+LauncherUI 触发 onResume 派发(设备机制非代码 bug)
    - _send_text_verified 轮询 message.status 直到 2,超时仍 1 视为已入队不误报
    - 拆 stage 目录(watcher=_stage / orchestrator=_stage_orch)避开拷库竞态
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • /whitelist 添加改为弹窗:默认列会话过的联系人/群(带昵称),搜索框查全量通讯录,
    复选框多选批量入库。新增 /api/contacts(会话列表) + /api/contacts/search(全量搜),
    /api/whitelist POST 支持批量 items。白名单存储/显示昵称+wxid/群id+类型。真机验证
    33 条默认列表、搜索、批量加(added:2)全通。viewer 改动全文见 wechat-viewer-changes.md。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • wechat_reply_orchestrator.py:消费 watcher incoming.jsonl(cursor增量+单实例锁+
    首跑基线)→ 候选事件(私聊/@我/引用我)→ env2 查上下文(rcontact身份+历史,一次拷库
    全批复用)→ env3 hermes -z 生成 → env4 policy.decide(白名单读 circle.db)→ env5
    落地(auto:send_text_via_hook+auto_sent / review:pending 进 /approvals)。生成失败
    即静默不发,绝不误发。watcher._trigger_orchestrator 读到新消息后 fire-and-forget
    拉起 drain(独立进程不阻塞采集)。真机验证:接线自动触发、真实猎头上下文生成火星人
    口吻草稿并正确进审核队列。auto_send 默认关=全审核(保守起步)。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • wechat_reply_policy.py:确定性安全闸 decide()→skip|auto|review,default-deny
    +敏感词硬override(钱/承诺/约时间白名单也拉回),demo 8/8 过。配置与审批 UI 落在
    手机端 ~/wechat-viewer(Flask):新表 reply_whitelist/reply_queue、/whitelist
    白名单页、/approvals 审批页(可编辑草稿+发送/取消),发送复用 send_text_via_hook。
    真机验证白名单增删查、发送到 filehelper(sent)、取消(cancelled) 全通。viewer 改
    动全文见 wechat-viewer-changes.md + viewer_templates/(不复制用户整个 app)。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »

  • 环节3 不写代码,Hermes 本身生成(deepseek-v4-pro/gateway),走 hermes -z 一次性
    调用(裸端点 8642 需鉴权,401,不用)。SOUL.md 从默认 Hermes 人设改为「火星人的
    手机助手」(替他回微信用其口吻+涉钱/承诺/约时间交本人确认;设备原文已备份)。
    真机验证质量:陌生猎头→「暂不考虑,谢谢」、熟人约饭→「可以啊,几点?在哪吃」,
    均在口吻上。观察:人设的安全约束是软的(约饭仍主动接话),硬门要落到环节4。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »
  • 环节2 无需新代码:Hermes 是有 shell+SQL 的 agent,给 wechat-db-decrypt skill
    补「读会话上下文」一节即可——一次拷库查齐发送者身份(rcontact,显示名优先级
    conRemark>nickname>alias)、最近 N 条历史(剥群 wxid: 前缀/type→占位符/只喂
    文本)、refermsg 引用解析 + 群名,并给出喂环节3 的上下文骨架。真机验证配方
    产出干净上下文。仓库留档 skill/wechat-db-decrypt-SKILL.md。
    
    Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
    yibo authored
     
    Browse Code »