news 2026/10/7 19:28:27

Xposed 获取微信好友列表(通讯录),TaoToken 统一 Key 通道下的抓取链路拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Xposed 获取微信好友列表(通讯录),TaoToken 统一 Key 通道下的抓取链路拆解

1. 从通讯录页面到 Cursor:Xposed 抓取微信好友列表的真实链路

微信通讯录这个页面,看起来只是一个普通列表,但真要从里面把好友列表完整拿出来,绕的弯比想象中多。我一开始也以为直接 Hook 一个getView或者某个 adapter 的getItem就能拿到数据,结果发现列表项布局 ID 是混淆过的,类名、方法名全是a、f、dy5这种,静态分析能看懂逻辑,但定位数据源要一层层往上翻。

这篇要解决的核心问题很具体:在 Android 逆向场景下,用 Xposed 模块 Hook 微信通讯录接口,把好友列表字段和分页逻辑梳理清楚,并且用 TaoToken 统一 Key 通道做请求鉴权的验证动作,确认返回数据是否完整。适合已经会写基础 Xposed 模块、能看懂 jadx 反编译结果、想复现通讯录抓取链路的读者。

链路大致是这样:通讯录列表 → adapter 的getItem()→moveToPosition()→ 某个aaa()方法 → 拿到Cursor(实际类型是HRK)→ 从Cursor里按列读取com.tencent.mm.storage.f泛型对应的字段。关键点在于Cursor不是直接 new 出来的,而是通过一个静态方法c.axA()配合linkedList参数(里面装"weixin"字符串)生成的。Hook 住这个静态方法,就能拿到Cursor的构造参数,再反射调用Cursor的getColumnNames()和getString(),好友列表就出来了。

分页逻辑这块,微信通讯录并不是一次性把全部好友塞进一个Cursor,而是按一定批次查询。moveToPosition()配合getCount()决定了当前 adapter 能看到多少条。实测下来,Cursor的getCount()返回的是当前查询批次的总数,翻页时Cursor会重新查询或者复用。要核对数据完整性,就得在 Hook 里记录每次Cursor的getCount()和实际读取到的行数,对比通讯录页面滚动到底部时的总数。

TaoToken 在这里的角色是统一 Key 通道。逆向过程中经常需要把抓到的数据发到自己的服务端做校验,或者调用模型接口做字段解析、去重、格式化。如果每个请求都单独配 Key,管理起来很乱。TaoToken 的 API 地址是https://taotoken.net/api,用统一 Key 做鉴权,请求头里带Authorization: Bearer <你的Key>,就能把抓取到的数据发出去做验证。这样抓取链路和鉴权链路分开,调试的时候不会互相干扰。

2. TaoToken 统一 Key 通道前置准备:Base URL、Key 与 Model ID 三件套

在开始 Hook 之前,先把 TaoToken 的通道配好。这一步不是可选项,因为后面验证请求、核对返回数据都要用到。TaoToken 的官网是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,API 地址是https://taotoken.net/api,注意 API 地址后面不加 UTM 参数,直接用于代码里的 Base URL。

你需要准备三件套:Base URL、API Key、Model ID。Base URL 就是https://taotoken.net/api,API Key 在控制台的 API Keys 页面生成,Model ID 根据你要调用的模型来选。比如做字段解析可以用通用对话模型,做代码辅助可以用 coding 专用模型。这三件套在后面的配置片段里会反复出现,先记下来。

如果你用的是 Claude Code 或者类似的编码工具,TaoToken 也支持通过配置文件接入。比如在settings.json里配置:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "你的TaoToken Key", "ANTHROPIC_MODEL": "你的Model ID" } }

这个配置片段可以直接复制,路径和原文一致。注意ANTHROPIC_BASE_URL后面不要加斜杠,ANTHROPIC_AUTH_TOKEN填你在 TaoToken 控制台生成的 Key,ANTHROPIC_MODEL填模型 ID。配好之后,Claude Code 的请求就会走 TaoToken 的统一 Key 通道。

如果你用的是 Cline 或者 Roo Code 这类插件,配置方式类似,在 MCP 或者 API 配置里填 Base URL、Key、Model ID。Cline 的 MCP 配置里,Base URL 填https://taotoken.net/api,Key 填 TaoToken 的 Key,Model ID 填对应模型。这样插件在调用模型时,鉴权就走 TaoToken,不用每个插件单独配。

Codex 的auth.json配置也类似,把 Base URL 和 Key 填进去就行。三件套的核心逻辑是一样的:Base URL 指向 TaoToken 的 API 地址,Key 做鉴权,Model ID 指定模型。配好之后,你可以先用一个简单的请求验证通道是否通:

curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer 你的TaoToken Key" \ -H "Content-Type: application/json" \ -d '{ "model": "你的Model ID", "messages": [{"role": "user", "content": "ping"}] }'

如果返回正常,说明通道没问题。这一步做完,再进入 Xposed 模块的配置和 Hook 点定位。

3. 可复制配置:Xposed 模块 Hook 微信通讯录接口的完整片段

现在进入正题,写 Xposed 模块。先确认环境:一台 root 过的 Android 设备或者模拟器,装了 Xposed 框架(或者 LSPosed),微信版本要和你反编译的版本一致。我实测用的是微信 8.x 某个版本,类名和方法名可能随版本变化,但链路逻辑是一样的。

模块的build.gradle里加 Xposed 依赖:

dependencies { compileOnly 'de.robv.android.xposed:api:82' }

AndroidManifest.xml里声明 Xposed 模块:

<application> <meta-data android:name="xposedmodule" android:value="true" /> <meta-data android:name="xposeddescription" android:value="Hook 微信通讯录 Cursor" /> <meta-data android:name="xposedminversion" android:value="82" /> </application>

主 Hook 类实现IXposedHookLoadPackage,在handleLoadPackage里判断包名com.tencent.mm,然后 Hook 目标方法。根据前面的链路分析,关键 Hook 点是那个静态方法c.axA(),它接收一个linkedList参数,返回Cursor。Hook 代码大概这样:

public class WeChatHook implements IXposedHookLoadPackage { @Override public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { if (!lpparam.packageName.equals("com.tencent.mm")) return; XposedHelpers.findAndHookMethod( "com.tencent.mm.storage.c", lpparam.classLoader, "axA", LinkedList.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { Object cursor = param.getResult(); if (cursor == null) return; // 反射调用 getCount 和 getColumnNames Method getCount = cursor.getClass().getMethod("getCount"); int count = (int) getCount.invoke(cursor); XposedBridge.log("Cursor count: " + count); Method getColumnNames = cursor.getClass().getMethod("getColumnNames"); String[] columns = (String[]) getColumnNames.invoke(cursor); for (String col : columns) { XposedBridge.log("Column: " + col); } } } ); } }

这段代码 Hook 住axA方法,在方法返回后拿到Cursor,反射调用getCount()和getColumnNames(),把列名和行数打到 Xposed 日志里。列名对应com.tencent.mm.storage.f的字段,比如username、nickname、conRemark这些。

如果你还想拿到具体数据,可以在 Hook 里遍历Cursor:

if (cursor.moveToFirst()) { do { StringBuilder sb = new StringBuilder(); for (String col : columns) { int idx = cursor.getColumnIndex(col); String val = cursor.getString(idx); sb.append(col).append("=").append(val).append("; "); } XposedBridge.log("Row: " + sb.toString()); } while (cursor.moveToNext()); }

注意Cursor的moveToPosition()和moveToNext()会改变游标位置,如果 adapter 也在用同一个Cursor,你的遍历可能会影响它的显示。实测下来,最好在 Hook 里先moveToPosition(-1)再遍历,或者复制一份Cursor数据。分页逻辑就体现在getCount()上,每次翻页Cursor的getCount()可能不同,记录每次的值就能看出分页批次。

TaoToken 的配置片段在这里也要用上。把抓到的数据发到 TaoToken 做校验,可以用一个简单的 HTTP 请求:

// 在 Hook 里收集完数据后,发到 TaoToken 做字段解析 JSONObject payload = new JSONObject(); payload.put("model", "你的Model ID"); payload.put("messages", new JSONArray().put( new JSONObject().put("role", "user").put("content", "解析以下好友数据: " + sb.toString()) )); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://taotoken.net/api/v1/chat/completions") .header("Authorization", "Bearer 你的TaoToken Key") .post(RequestBody.create(payload.toString(), MediaType.parse("application/json"))) .build();

这样抓取和鉴权就串起来了。Base URL、Key、Model ID 三件套在代码里都出现,路径和原文一致。

4. 验证请求与成功结果:核对返回数据是否完整

Hook 跑起来之后,怎么确认数据是完整的?分两步:先看 Xposed 日志里的Cursor列名和行数,再用 TaoToken 做一次请求验证。

启动微信,进入通讯录页面,滚动列表。Xposed 日志里会打印类似这样的内容:

Cursor count: 128 Column: username Column: nickname Column: conRemark Column: alias Column: type ... Row: username=wxid_xxx; nickname=张三; conRemark=; alias=; type=3; ...

Cursor count是当前批次的好友数,列名对应com.tencent.mm.storage.f的字段。如果你看到count是 128,但通讯录页面显示有 300 个好友,说明分页了,需要继续滚动触发下一批查询。每次axA被调用,都会打印一次count,把多次的count加起来,对比通讯录底部的总数,就能判断是否完整。

用 TaoToken 做验证请求,把日志里的数据发过去,让模型帮你核对字段是否齐全、有没有重复。请求成功返回类似:

{ "choices": [ { "message": { "content": "数据包含 128 条记录,字段 username、nickname、conRemark、alias、type 均存在,无重复 username。" } } ] }

如果返回里提到字段缺失或者重复,就回到 Hook 代码里检查是不是漏了某个列,或者Cursor遍历时没处理分页。实测下来,conRemark字段有时候为空,这是正常的,不是数据丢失。type字段区分好友类型,比如 3 是普通好友,其他值可能是公众号或者服务号。

验证请求的完整命令可以用 curl 复现:

curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer 你的TaoToken Key" \ -H "Content-Type: application/json" \ -d '{ "model": "你的Model ID", "messages": [ {"role": "user", "content": "核对以下好友数据字段是否完整: username=wxid_xxx; nickname=张三; conRemark=; alias=; type=3;"} ] }'

返回的choices里就是模型的核对结果。如果通道不通,会返回 401 或者local proxy failed,这时候检查 Key 和 Base URL 是否正确。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

Hook 和验证过程中,最容易遇到的几个报错,我一个个说。

401 Unauthorized:TaoToken 请求返回 401,说明 Key 不对或者没带。检查Authorization头是不是Bearer <你的Key>,Key 有没有复制错。如果你用的是 Claude Code 的settings.json,检查ANTHROPIC_AUTH_TOKEN是不是填了 TaoToken 的 Key,而不是其他平台的。Base URL 也要确认是https://taotoken.net/api,不要多写斜杠或者路径。

local proxy failed:这个报错通常出现在本地代理配置有问题的时候。如果你在代码里或者工具里配了本地代理,检查代理地址和端口。TaoToken 的请求不需要额外代理,直接连https://taotoken.net/api就行。如果工具里默认开了代理,关掉再试。Cline 或者 Roo Code 的 MCP 配置里,如果 Base URL 填错,也会报类似的错,确认三件套里的 Base URL 是https://taotoken.net/api。

reading choices 报错:这个通常出现在解析返回 JSON 的时候。TaoToken 返回的结构是{"choices": [{"message": {"content": "..."}}]},如果你直接读choices数组没判空,或者返回体不是预期格式,就会报reading choices相关的错。检查请求是否成功,返回体是不是 JSON,choices数组有没有元素。可以在代码里先打印完整返回体再解析。

OAuth 相关报错:如果你用的是 Claude Code 或者 Codex 的 OAuth 登录方式,可能会遇到 OAuth 报错。TaoToken 的接入不需要 OAuth,直接用 API Key 就行。在settings.json或者auth.json里,把 OAuth 相关的配置去掉,只保留 Base URL、Key、Model ID 三件套。Claude Code 的ANTHROPIC_AUTH_TOKEN填 TaoToken Key,不要走 OAuth 流程。

Hook 不生效:Xposed 模块装了但日志没输出,检查模块是否在 Xposed 管理器里启用,微信是否被选中。LSPosed 的话,检查作用域是否包含微信。另外,微信版本和反编译版本要一致,类名com.tencent.mm.storage.c和方法名axA可能随版本变化,用 jadx 重新确认。

Cursor 遍历影响列表显示:前面提过,遍历Cursor会改变游标位置,导致通讯录列表显示异常。解决办法是在 Hook 里先保存Cursor的 position,遍历完再恢复,或者用CursorWindow复制数据。实测下来,恢复 position 最省事:

int pos = cursor.getPosition(); // 遍历 cursor.moveToPosition(pos);

6. 语义一致 CTA:接入文档、API Keys 与模型对话

抓取链路跑通之后,如果你想把 TaoToken 的通道用到其他逆向或者数据校验场景,可以直接看接入文档,里面有不同工具和语言的配置示例。API Keys 页面用来生成和管理 Key,Coding Plan 适合长期做编码和 Agent 任务的场景,模型对话页面可以快速验证模型是否可用。

排障和接入相关的问题,优先看 API Keys 和接入文档;验证模型效果,用模型对话;长期编码或者 Agent 任务,看 Coding Plan。地址分别是:

  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
  • API Keys:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
  • 模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite
  • Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite

最后说一个实用技巧:Hook 微信通讯录的时候,Cursor的列名和com.tencent.mm.storage.f的字段是对应的,但字段顺序不一定和列名顺序一致。用getColumnIndex()按列名取,不要按索引硬编码。分页逻辑上,getCount()每次返回的是当前批次的数量,不是总数,要累加多次 Hook 的结果。如果发现某次count突然变小,可能是查询条件变了,检查linkedList参数里的"weixin"字符串有没有被替换成其他值。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 19:27:09

AI Agent Skills 实战指南:从安装到开发可复用能力模块

1. 从“skills”这个标题说起&#xff1a;它到底指什么第一次看到“skills”这个标题&#xff0c;很多人会以为是某个泛泛而谈的能力清单&#xff0c;或者一份简历上的技能罗列。但结合热搜词里的 Agent Skills、Google Cloud、npx、GKE、claude agent skills、codex skills 这…

作者头像 李华
网站建设 2026/10/7 19:26:38

Ricon组态系统实战:从零构建物联网监控平台

1. 项目缘起与整体设计思路1.1 为什么选择Ricon组态系统做物联网监控平台先说结论&#xff1a;如果你手头有一堆传感器、PLC、仪表&#xff0c;需要快速搭一个能看、能控、能报警、能存数据的监控界面&#xff0c;又不想从零写前端后端&#xff0c;Ricon组态系统是目前国内工控…

作者头像 李华
网站建设 2026/10/7 19:26:37

MCP——为你的大模型插上翅膀:从函数调用到Agent的Type-C式接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/7 19:26:33

Agent-Reach 实战:用 CLI 驱动 AI Agent 落地自动化

1. 从标题到落地&#xff1a;Agent-Reach 到底想解决什么问题第一次看到 Agent-Reach 这个名字&#xff0c;我下意识把它拆成了两半&#xff1a;Agent 和 Reach。Agent 是当下最热的 AI 智能体概念&#xff0c;Reach 则是“触达、够得着”的意思。合在一起&#xff0c;我的理解…

作者头像 李华
网站建设 2026/10/7 19:24:55

caveman极简编码代理:CLI配置、token优化与实操指南

1. 从“caveman”说起&#xff1a;一个极简编码代理的诞生逻辑第一次看到“caveman”这个词&#xff0c;脑子里蹦出来的画面就是拿着石斧、围着兽皮、用最原始的方式解决问题的远古人类。把这个词用在编码代理&#xff08;coding agent&#xff09;上&#xff0c;本身就带着一种…

作者头像 李华
网站建设 2026/10/7 19:24:49

数据标注与数据集制作是 YOLO11 工程中**最耗时但也最决定上限**的环节。一个模型的上限,在标注质量定下来的那一刻就已经确定了

数据标注与数据集制作是 YOLO11 工程中最耗时但也最决定上限的环节。一个模型的上限&#xff0c;在标注质量定下来的那一刻就已经确定了。 YOLO 格式&#xff1a;简洁的“归一化坐标”体系 YOLO 不直接用像素坐标&#xff0c;而是要求归一化到 0-1 之间。这是最常见的错误来源—…

作者头像 李华