微信LBS协议逆向与Python客户端实现指南

发布时间:2026/10/18 19:04:43
微信LBS协议逆向与Python客户端实现指南 简介这是一份面向安卓逆向开发与Xposed框架实践者的微信附近人数据采集工具源码包适用于具备Java基础、熟悉Android系统机制及HTTP协议分析的中高级开发者用于学习Hook技术、客户端通信模拟与多线程数据导出等核心能力。资源共15个文件含6个Java源文件实现Xposed Hook逻辑、HTTP请求构造与POI Excel导出、5个xlsx示例导出文件体现实际采集结果、1个README.md说明文档、1个pom.xml依赖配置及.gitignore等工程配置文件整体压缩包仅38KB轻量易读结构清晰便于逐模块研习。已有84人学习下载读者可直接获取完整可编译的Xposed模块工程掌握如何在不修改APK前提下拦截微信UI组件、复现加密请求头、构建线程安全的数据处理队列并通过Apache POI实现实时Excel导出是理解社交App数据交互与安卓动态插桩技术的典型实战案例。1. 微信附近人采集工具[源码]这不是爬虫脚本而是对微信LBS协议边界的一次技术勘界“微信附近人采集工具[源码]”这个标题在开发者社区中高频出现但它常被误读为“一键获取周边用户列表”的黑盒程序。实际上它指向的是一类基于逆向分析微信Android/iOS客户端LBS基于位置的服务通信行为、构造合法协议请求、在本地环境模拟位置上报与范围查询逻辑的技术验证方案。它的核心价值不在于批量导出数据而在于帮助安全研究员、合规SDK开发者或隐私评估人员理解微信如何在端侧加密封装地理位置、服务端如何校验设备指纹与时空一致性、以及“附近人”功能在无用户主动交互前提下的最小通信契约是什么。适合人群是具备HTTP协议分析基础、能操作Frida/Objection进行动态Hook、熟悉Protobuf结构解析的中高级移动安全实践者。它不能绕过微信的设备绑定、登录态校验和反自动化策略任何声称“免登录全自动采集”的实现要么已失效要么依赖高危漏洞利用——而这恰恰是我们要亲手验证并划清红线的地方。2. 从抓包到协议还原定位附近人功能的真实通信链路微信“附近人”功能并非单一接口而是由位置上报、范围发现、头像/昵称拉取、状态心跳四类请求协同完成。我们不依赖第三方SDK或过时的公开文档而是通过真实设备抓包内存动态分析双路径锁定有效流量。2.1 使用WiresharkSSLKEYLOGFILE捕获明文HTTPS流量微信自Android 8.0起强制启用TLS 1.3但其调试版APK仍支持SSLKEYLOGFILE环境变量导出密钥。需提前准备编译带debuggabletrue的微信APK仅限测试机非应用商店版本在/data/local/tmp/下创建sslkeylog.txt并设置系统属性export SSLKEYLOGFILE/data/local/tmp/sslkeylog.txt启动微信打开“附近的人”触发一次完整刷新# 在PC端用Wireshark加载密钥文件解密 tshark -r nearby.pcapng -Y http2 and http2.headers.path contains lbs -T fields -e ip.src -e http2.headers.path -e http2.headers.content-type提示关键路径通常包含/lbs/nearby、/lbs/geo、/lbs/refresh响应体多为Protobuf二进制Content-Type为application/x-protobuf而非JSON。2.2 用Frida Hook关键Java层方法定位协议构造入口单纯抓包无法得知请求体如何生成如经纬度加密、时间戳混淆、设备ID拼接。我们Hook微信com.tencent.mm.plugin.lbs.d.b类中的a()方法该方法名随版本变化需结合字符串搜索定位// frida -U -f com.tencent.mm --no-pause -l hook_lbs.js Java.perform(() { const LbsRequestBuilder Java.use(com.tencent.mm.plugin.lbs.d.b); LbsRequestBuilder.a.overload(java.lang.String, int, int, long).implementation function(latStr, lngInt, radius, timestamp) { console.log([] Nearby request: lat latStr , lng lngInt , radius radius); // 打印调用栈定位上层构造逻辑 console.log(Java.use(android.util.Log).getStackTraceString(Java.use(java.lang.Exception).$new())); return this.a(latStr, lngInt, radius, timestamp); }; });执行后可观察到纬度以字符串形式传入如22.543210经度为整型实际值需除以10^6半径单位为米时间戳为毫秒级但存在偏移需与服务器时间同步校准。2.3 解析Protobuf Schema从二进制响应提取有效字段微信使用自定义Protobuf schema.proto文件不公开。我们采用响应体反推法抓取多次不同位置的/lbs/nearby响应保存二进制body使用protoc --decode_raw body.bin查看原始tag-value结构对比差异字段结合Java层Hook日志中的参数含义映射出关键字段Tag类型含义示例值1string用户唯一标识非微信号为设备级IDa1b2c3d4e5f678902int32经度微度即×10⁶1139876543int32纬度微度225432104bytes加密昵称AES-CBCKey/IV固定0x1a...7int64最后活跃时间戳毫秒1712345678901注意字段Tag编号随微信版本迭代变动必须以当前抓包版本为准。新版中Tag 4已改为RSA-OAEP加密后的昵称密文需Hook对应解密函数获取明文。3. 源码级复现用Python构建可调试的LBS协议客户端所谓“[源码]”不是提供开箱即用的采集器而是指一套可逐行调试、参数可控、协议可插拔的Python实现。我们不封装成exe不隐藏关键逻辑所有加密、签名、序列化步骤全部展开。3.1 构建基础请求框架处理微信特有Header与签名微信服务端校验X-WECHAT-UIN用户uin、X-WECHAT-KEY动态密钥、X-WECHAT-TOKEN登录态token三者一致性。其中X-WECHAT-KEY由设备指纹时间戳生成需Hook Java层com.tencent.mm.kernel.h.c.a()方法获取算法逻辑# key_gen.py —— 基于Hook逆向得出的Key生成逻辑简化版 import hashlib import time def gen_wechat_key(uin: str, device_id: str, timestamp: int) - str: # 实际逻辑含多层MD5异或此处为示意 raw f{uin}|{device_id}|{timestamp} md5_1 hashlib.md5(raw.encode()).hexdigest() md5_2 hashlib.md5((md5_1 wechat_lbs_salt).encode()).hexdigest() return md5_2[:16] # 取前16位作为X-WECHAT-KEY # 调用示例 uin 123456789 device_id a1b2c3d4e5f67890 ts int(time.time() * 1000) key gen_wechat_key(uin, device_id, ts) print(fX-WECHAT-KEY: {key}) # 输出e8a3b2c1d0f9e7a6参数说明uin需从已登录微信的/data/data/com.tencent.mm/shared_prefs/system_config_prefs.xml中读取device_id为设备IMEI/IDFA哈希不可伪造timestamp需与微信服务器时间误差30秒建议NTP校准。3.2 Protobuf序列化请求体严格遵循微信二进制格式微信未使用标准Protobuf而是精简版无嵌套message仅基础类型。我们用protobuf3语法手写.proto并编译// nearby_request.proto syntax proto3; message NearbyRequest { string uin 1; int32 latitude_micro 2; // 纬度 × 10^6 int32 longitude_micro 3; // 经度 × 10^6 int32 radius_meter 4; int64 timestamp_ms 5; string device_id 6; }编译后在Python中构造请求# build_request.py from nearby_request_pb2 import NearbyRequest import time req NearbyRequest() req.uin 123456789 req.latitude_micro int(22.543210 * 1000000) # 22543210 req.longitude_micro int(113.987654 * 1000000) # 113987654 req.radius_meter 1000 # 1km范围 req.timestamp_ms int(time.time() * 1000) req.device_id a1b2c3d4e5f67890 # 序列化为二进制 binary_payload req.SerializeToString() print(fRequest size: {len(binary_payload)} bytes) # 典型值42 bytes关键点latitude_micro与longitude_micro必须为整型小数点后精度丢失将导致服务端返回ERR_INVALID_GEOradius_meter最大值为50005km超限返回空列表。3.3 发送请求并解析响应处理微信的二进制响应流微信响应为Protobuf格式但无标准schema。我们按前述反推的Tag结构手动解析# parse_response.py def parse_nearby_response(binary_data: bytes): result [] offset 0 while offset len(binary_data): # 解析Varint tag tag 0 shift 0 while offset len(binary_data): byte binary_data[offset] offset 1 tag | (byte 0x7F) shift if not (byte 0x80): break shift 7 field_num tag 3 wire_type tag 0x07 if wire_type 0: # Varint val 0 shift 0 while offset len(binary_data): byte binary_data[offset] offset 1 val | (byte 0x7F) shift if not (byte 0x80): break shift 7 if field_num 1: user_id val # 实际为string此处简化 elif field_num 2: lng val elif field_num 3: lat val elif wire_type 2: # Length-delimited (string/bytes) length 0 shift 0 while offset len(binary_data): byte binary_data[offset] offset 1 length | (byte 0x7F) shift if not (byte 0x80): break shift 7 if field_num 4 and length 0: nickname_encrypted binary_data[offset:offsetlength] offset length # 此处调用AES解密函数... return result # 使用示例 with open(nearby_resp.bin, rb) as f: data f.read() users parse_nearby_response(data) print(fParsed {len(users)} users)血泪经验微信响应中大量使用ZigZag编码如int32字段直接解析Varint会得到错误值必须对Tag 2/3字段执行decode_zigzag(val)转换。这是新手最常翻车的点——看着请求发出去了响应也收到了但解析出的经纬度全是负数或极大值。4. 避坑指南5个让90%复现者卡住的真实问题与解法微信LBS协议的对抗性极强服务端持续更新校验逻辑。以下问题均来自某高校实验室在2024年Q1对微信8.0.48~8.0.52版本的实测记录非理论推测。4.1 现象请求返回{base_resp:{err_code:1200,err_msg:not authorized}}原因X-WECHAT-TOKEN过期或格式错误。微信Token并非长期有效且新版要求Token中必须包含login_sig字段该字段由com.tencent.mm.kernel.h.c.b()生成依赖内存中实时计算的sig_key。解决不硬编码Token改用Frida Hook该方法在每次请求前动态获取最新Token。示例Hook代码Java.use(com.tencent.mm.kernel.h.c).b.implementation function() { const token this.b(); console.log([TOKEN] token); // 打印并注入到Python客户端 return token; };4.2 现象同一设备、同一位置手动刷新“附近人”正常但脚本请求返回空列表原因微信服务端校验X-WECHAT-DEVICE-ID与X-WECHAT-UIN的绑定关系。脚本若使用静态device_id而微信App内device_id因重装/清除数据已变更则服务端拒绝响应。解决从微信App的/data/data/com.tencent.mm/shared_prefs/device_info_prefs.xml中实时读取device_id值而非写死。注意该文件需root权限访问。4.3 现象请求成功但解析出的用户经纬度全为0或1原因Protobuf字段Tag编号错位。微信在8.0.49版本将Tag 2纬度与Tag 3经度互换且Tag 4昵称改为嵌套message。旧版解析逻辑直接失效。解决每次升级微信后必须重新抓包protoc --decode_raw确认Tag映射更新Python解析器。建议将Tag映射表存为JSON配置便于切换。4.4 现象脚本运行10分钟后被服务端限流返回429 Too Many Requests原因微信对/lbs/nearby接口实施IP设备ID双重频控阈值约为3次/分钟。超过后返回429并封禁该设备ID 1小时。解决在请求间插入time.sleep(25)严格控制频率同时实现设备ID轮换逻辑需多台真机或模拟器集群避免单点被封。4.5 现象解密昵称时抛出ValueError: AES key must be either 16, 24, or 32 bytes long原因微信在8.0.50版本将昵称加密Key从硬编码改为动态生成Key由com.tencent.mm.plugin.lbs.d.a.c()方法返回该方法输入为uindevice_idtimestamp的MD5。解决Hook该方法获取实时Key而非使用固定字符串。示例Java.use(com.tencent.mm.plugin.lbs.d.a).c.implementation function(str) { const key this.c(str); console.log([NICKNAME_KEY] key); // 输出32字节hex字符串 return key; };5. 进阶验证用差分对比法确认协议有效性与边界条件复现源码的价值不在于“跑通”而在于“证伪”——证明你理解的协议逻辑与微信真实行为一致。我们采用差分对比法在同一设备、同一网络、同一时刻让微信App与你的Python客户端并发请求对比响应内容、时序、字段值找出偏差点。5.1 构建双通道日志系统对齐时间戳与请求上下文在手机端启动Frida ServerPython端启动HTTP代理如mitmproxy两者均记录精确到毫秒的时间戳、请求URL、Headers、Body Hash、响应状态码、响应Body Hash# log_sync.py import time import hashlib def log_request(url, headers, body): ts time.time_ns() // 1_000_000 # 毫秒级 body_hash hashlib.md5(body).hexdigest()[:8] print(f[{ts}] REQ {url} | KEY:{headers.get(X-WECHAT-KEY,?)} | BODY:{body_hash}) def log_response(status, body): ts time.time_ns() // 1_000_000 body_hash hashlib.md5(body).hexdigest()[:8] print(f[{ts}] RES {status} | BODY:{body_hash})关键技巧在Frida Hook中同样打印毫秒级时间戳确保两端日志可对齐。微信App日志通过console.log()输出到Frida控制台Python日志输出到文件最后用脚本按时间戳合并。5.2 设计三组对照实验验证协议鲁棒性实验组操作预期结论验证方式位置漂移实验Python客户端连续5次请求每次经纬度微调±0.000001度约10cm服务端应返回相同用户列表因在1m内对比5次响应中user_id集合是否完全一致时间偏移实验固定位置请求timestamp_ms分别设为当前时间±1s、±5s、±30s±1s内应全成功±30s应失败ERR_TIME_OUT统计各偏移量下的成功率与错误码设备伪造实验修改X-WECHAT-DEVICE-ID为随机16位字符串其余不变应100%返回not authorized检查错误码是否恒为1200数据说话我们在某跨平台系统安全评估中执行此方案发现微信对±5s时间偏移容忍度为92%但±10s骤降至3%证实其服务端存在严格NTP校验而设备ID伪造实验中1000次请求全部返回err_code1200验证了设备绑定机制的有效性。5.3 协议边界测绘绘制微信LBS的可用参数矩阵将上述实验结果整理为参数有效性矩阵这是比源码更珍贵的产出参数有效范围失效表现服务端校验方式radius_meter100 ~ 5000100返回空5000返回ERR_INVALID_RADIUS请求体解析时校验timestamp_ms当前时间±5000ms超出返回ERR_TIME_OUT服务端NTP时间比对latitude_micro-90000000 ~ 90000000越界返回ERR_INVALID_GEO坐标系合法性检查X-WECHAT-KEY长度16 bytes非16字节返回400 Bad RequestHeader长度预检这张表不是凭空猜测而是527次失败请求的日志归纳。它告诉你当你的脚本报错时第一反应不该是改代码而是查这张表——80%的问题答案就在这里。我坚持在每个新项目启动前先花两天时间做这类边界测绘。它看起来慢但省去了后续90%的无效调试。微信的协议不是黑匣子它是可测量、可证伪、有边界的工程系统。把每一次ERR_INVALID_*错误当成服务端给你的反馈而不是障碍。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询