微信逆向之朋友圈,微信朋友圈之获取小视频地址、图片加解密,微信聊天机器人,微信朋友圈克隆,微信数字人、客服、二次开发、About PC微信Hook模块、Hook WeChat / 微信逆向、微信机器人。
最终效果
本软件可以补充官方做不到的功能,例如可以获取到所有类型的消息,进行消息存档,也可以调用接口去自动化处理一些事项,详情接口看菜单。
开放平台是基于微信开放平台的二次封装API服务,开发者可以使用本服务来处理微信中的各种事件,并可以通过后台调用对应的 API 来驱动微信自动执行任务,如自动收发消息、自动化应答、自动群邀请、群管理等,封装了RPA技术流程,简化开发者二次开发难度,提供了开发者与微信对接的能力,使用简单,操作快捷,支持多种语言接入。
环境 环境需要 Windows 系统,可以是家用电脑也可以是服务器。无公网IP也可照常调用接口.
消息回调 本文档不枚举所有接收消息(具体查看文档,pc版所有的消息都能够订阅)
常见开发功能: 好友管理:添加好友、删除好友、修改备注、创建标签、获取好友列表、搜索好友信息 消息管理:发文本消息、图片消息、名片消息、动图表情、小程序、发文件、发送视频、发送URL链接 群管理:自动创群、修改群名称、邀请新成员、踢群成员、获取群列表、发送邀请链接、获取群聊 朋友圈:发送朋友圈、朋友圈点赞、获取朋友圈列表、转发朋友圈、同步朋友圈 基于API您可以创造更多有趣的功能…
常见开发产品: 平台系统类:淘宝客云发单平台、私域营销平台、AI智能客服系统、员工微信监管平台、企业内部批量化管理系统等。 功能类:告警类机器人(例:地震告警、极端天气、服务器宕机、敏感话题、违规内容)、问答类机器人(例:百科,内容查询类),自定义业务类机器人(例:结合场景自定义开发)。 业务类:城市网格员群内问答类、政府内部业务类(例:地震信息通报、城市网格员关键字回复)、群内关键字触发(人工/自动回复),电商发单返利类,私域群营销业务及批量化管理类等
开发原理: 本平台采用自研RPA响应框架,非hook类侵入式修改,使用OS原生定制化系统,且使用了原生支持的无障碍服务点击能力,无需用户手机Root,只需用户扫码授权即可接入使用。 本平台服务支持公有云服务SAAS/私有化部署方式,如您对数据和使用场景比较敏感,建议私有化部署,常规开发建议SAAS服务即可,SAAS服务仅是路由转发,不存储用户敏感内容数据。 新注册账号/未实名账号/被封过的账号属于低质量账号,请勿在本平台使用!先确保账号已实名且正常使用方可接入平台。 如果您的账号曾有被封行为,请勿使用本平台!如您的行为违反微信运营规范或国家相关法律规定,请勿使用本平台!
本平台采用自研RPA响应框架,非hook类侵入式修改,使用了原生支持的无障碍服务点击能力,只需用户扫码授权即可接入使用。 本平台服务支持公有云服务SAAS/私有化部署方式,如您对数据和使用场景比较敏感,建议私有化部署,常规开发建议SAAS服务即可,SAAS服务仅是路由转发,不存储用户敏感内容数据。 新注册账号/未实名账号/被封过的账号属于低质量账号,请勿在本平台使用!先确保账号已实名且正常使用方可接入平台。 如果您的账号曾有被封行为,请勿使用本平台!如您的行为违反微信运营规范或国家相关法律规定,请勿使用本平台!
API接口文档
https://bf27ycsiyy.apifox.cn/318180794e0
部署运行(仅仅举例)
1、启动微信,并登陆(数据完全在本地,安全放心):
2、调用接口查看好友列表,获取微信的相关信息:
3、调用接口获取好友的朋友圈数据
其它服务
你想要的都有。
接入排查参考 说明: 新注册账号/未实名账号/被封过的账号属于低质量账号,请勿在本平台使用!先确保账号已实名且正常使用方可接入平台。
一、掉线问题排查 目前新用户登录API平台,24小时内首夜会100%掉线,掉线后传appId调用获取二维码接口再次扫码登录即可实现3月内不掉线,目前已知会导致微信掉线的情况有: 可能性1: 微信登录地点是异省,则必然出现秒掉,且每次登陆都会掉线(需使用本省代理),若使用本省代理方式登录,且登录也出现60秒内掉线,且传appId再次取码登录依然秒掉,则进入新设备风控,第二天8点后必然可以正常登录使用。 可能性2: 微信登录IPad真机或者手机退出微信或者换了手机登录微信,导致挤掉线 可能性3: 登录本平台未满2天的微信属于非安全环境,非安全环境下禁止频繁触发敏感行为(群发同质化内容、添加好友,自动同意好友、创建群聊,入群)等,容易触发各类异常风控,建议在线1~2天后在做频繁操作。 可能性4: 首夜掉线后一定记得传appId获取二维码扫码登录,这样才会登录上次登录的设备,否则就会循环陷入掉线的情况(严重者则封号),判断是否陷入循环掉线,可在手机微信 设置-账号与安全-登录过的设备 查看,如果存在多个ipad开头的即代表是错误的。
二、消息发送规范 核心: 尽量像人为在操作。 1.消息发送频率建议 1min建议40条左右,每个不同用户切换间隔1S,不同群发送间隔随机2-5S,消息需走队列形式。 2.为什么消息发送失败 可能性1: 小程序消息每日会有条数限制(WeChat规范限制) 可能性2: 发送对象不存在/群被踢出/好友被删除等 可能性3: 消息发送过快导致,手机会显示发送频率过快请稍后重试 可能性4: 消息发送不能存在并发,必须走消息队列消费发送(一个调用发送成功后,在调用下一个事件消费) 3.为什么群消息有的人看不见 在腾讯内部规则中,发送同质化内容过多,或者疑似营销内容以及发送量快会导致此问题,会降权此条消息内容有效到达数,随机性推送可看到的用户,可用手机测试 4.为什么图片/视频/文件消息发送慢 图片/视频/文件的服务器的速度会导致此问题,发送图片/视频/文件接口的原理是我们将资源的url下载我们服务器中然后在转换成认可的资源发送,可以多通过网络图片测试对比是否是是图片服务器慢的问题。 5.很多个微信发送同样内容或单个微信同样内容发送给很多好友的优化方式? 说明: 本场景多适用于云发单及社群机器人,如若1000个微信需要发单,不要直接调用发送图片/视频/文件接口(直接发送会每张微信都上传图片/视频/文件,重复消耗流量,占用网速),如下所示,有以下3种解决优化方案: 第一种方案: 找2个机器人创建个素材群(素材机器人+素材接收机器人),把图片/视频/文件让素材机器人发送接口发到素材群,素材接收机器人会收到图片/视频/文件的XML,后续直接让发单机器人根据xml调用转发图片/视频消息接口即可(转发接口无上传操作,效率提升几十倍),不限制发单机器人是否在群内,有xml就可以发。 第二种方案: 先把文件/图片/视频发送至额外的机器人,通过消息回调获取文件消息的 xml 后,使用转发文件/图片/视频接口发送(转发接口无上传操作,效率提升几十倍) 第三种方案: 发送相同的图片的话,随便找1个微信直接调用CDN图片/视频上传接口,拿到返回秘钥,其他微信就不调用上传接口,而是直接调用转发接口(上传图片的微信和直接使用转发接口的微信可以毫无关系)动态组装下转发接口xml就可发送(转发接口无上传操作,效率提升几十倍)。
三、消息接收问题排查 1.消息接收慢 可能性一: 用户接口的死锁,堵塞,多线程处理错乱,接口业务处理消息时间过长会导致此问题,具体开发者可以自行使用postman测试下自己接口或者登录后台系统查看回调是否正常 可能性二: 在腾讯内部规则中,发送同质化内容过多,群过多,群消息过多,或者疑似营销内容以及发送量快会导致此问题,会降权此条消息内容有效到达数,随机性推送可看到的用户,可用手机测试是否正常。或者以多个机器人微信作为协助。 2.消息接收不到 排查一: 首先开发者需确认提供的服务器接口是可以通的,微信的消息回调会以post请求 json参数的格式请求开发者服务器接口。开发者也可以使用postman测试下自己接口是否正常 排查二: 开发者需确认微信没被踢掉线,确认是否在线是 以调用发送文本消息接口或者查询微信是否在线接口成功为准,注意:通过接口发送的消息不会有回调。
四、好友相关问题 1.添加好友接口调用规则 24 小时只能加 5-15 位好友,每 2 小时不要超过 8 人,每个好友添加间隔要做随机间隔,否则添加了对方,显示发送验证成功,对方也收不到你的验证信息。(新登录平台的微信需在线3天调用本接口) 2.同意好友接口调用规则 根据微信号权重,微信每天被动通过好友数不要超过 200 人,过多扫二维码添加也有封 号风险,并且一天太多人添加,你的微信将收不到别人的验证消息。 3.搜索好友调用规则 搜索好友数量每日大概在10-20之间,具体可手机,调用需做好间隔。
五、群相关问题 1.如何获取群内非好友的微信号 微信新规,无法查看微信号 2.为什么接口返回的群少了或者没有 接口一次性是获取不是全部的群,仅会获取保存到通讯录的群,当有未获取的群有人在群内发消息的话会有消息回调, 开发者此刻调用获取群详情接口 再保存到自己数据库中就取到了,比如说手机上三年前不说话的群,侧滑删除了,然后你换了手机也不会取到的 ,有人说了话他才会置顶,原理就是各个终端(Android、IOS、桌面版微信)取得了消息回调,又去获取群了详情 本地数据库缓存了下来 更新的ui,让用户感知的。 3.创建群聊规范 每天只能添加10个群,频率间隔在10分钟以上。如果建群数量超出, 或者频率过快,就会返回失败,具体可根据微信号适当增减。 4.获取群二维码接口扫描显示已过期 新登录API平台的微信用户需在线3天后调用获取群二维码,此时群二维码才可以正常使用。
六、朋友圈问题 1.朋友圈接口调用规则 获取动态接口建议最低间隔5S/次,一天不要超过200次 点赞评论接口建议间隔随机3-10s/次,一天不要超过500条 2.发送朋友圈为什么返回失败 新登录API平台的微信用户需在线1天后才可正常发送朋友圈 3.发送朋友圈/评论自己看得到,别人看不到 可能一: 朋友圈或者评论发多了或导致此问题,腾讯选择性推送 可能二: 某些屏蔽的关键字也会导致此问题(比如淘客行业的评论文字,原文字会被拦截屏蔽,需开发者修改下部分文字去适配) 可能三: 图片内容或者文字违法违规
七、下载问题 1.下载接口调用规则 下载必须要设置下载队列,每条消息的下载要与上条间隔3-10S(随机time) 一条消息只下载一次 2.下载接口为什么返回失败 无论是下载图片、语音、链接、视频、假如频繁下载皆有可能导致此问题,我们对于这类建议如下:适配调用规则,千万别收到消息就下载!!!,否则容易失败甚至被踢掉线,一定要做下载队列,假如觉得下载时间太长业务不满足,可以多放几个僵尸微信/转发图片到其他机器人再做下载使用 文件下载失败: 除了上述频率问题,还有可能是因为回调有两条,开发者应选择第二条下载 图片下载失败: 除了上述频率问题,图片下载失败有可能不存在普清/高清,需重试几次其他种类
八、其他问题 1.微信号显示问题 在调用获取通讯录信息接口中,微信原始id有时候返回是手机上的微信号,也有的是没有微信号,仅有wxid开头的,导致开发者有点混乱,其实这是微信的内部规则,微信原始id就是获取通讯录接口返回的,alisname为空,则代表该微信没有微信号,仅有wxid,具体理解下如图即可。
2.风控问题? 敏感类接口: 添加好友、同意好友、获取群二维码、创建群聊为敏感接口,建议非异地登录且安全环境下再做操作,否则会有一定几率风控,目前部分敏感接口已需强制在线几天,方可操作接口 安全环境: 登录未满48小时属于非安全环境,一般新用户微信登录24小时内会掉线一次,传wxid取码登录后再隔一天就属于安全环境。 异地登录: 扫码登录显示其他城市,可使用本地代理登录解决/私有化部署本地服务。 严格按照本调用规范手册则可避免99.99%技术风控,但部分敏感行为操作仍会导致使用规范风控,常见敏感行为:(异地环境下/非安全设备环境下添加好友和自动同意好友,群发内容、拉群及图片违法违规,接口使用间隔频率像机器人等) 目前部分敏感接口已需要强制在线几天方可使用,规则如下: 获取群二维码接口3天 (官方限制) 发送朋友圈类接口1天 (官方限制) 获取群二维码接口3天(官方限制)
常见问题: Q. 每天发送内容数量是否有限制? 服务没有限制,但是微信本身有规则限制,例:发送频率是否过快、发送内容是否违规等,建议开发者做好频率控制,消息发送类必须走队列消费,做好消息间隔,勿并发。 Q. 单个机器人同时支持多少人/群的聊天? 严格来说,机器人若是只挂机则无上限,具体需要根据活跃度而定,例如一条消息,普通人正常发送1~2秒,1分钟则建议20-40条消息,根据消息量和开发者可接受的的回复速度去换算同时支持的人/群。 Q. 单个Token最多支持多少微信? 根据采购数量,单个Token可绑定微信数量无上限。 Q. 只用单个Token和使用多个Token的意义? 1个Token可设置一个回调接口,采购多个机器人服务,可以配置多个Token,可设置多个回调地址。 Q. 一个开发者账号可以生成多少个Token? 根据采购数量,例如采购10个机器人,则最多可生成10个Token(平台默认生成1个,可通过API后台系统生成多个,也可以10个微信都登录到1个Token下),平台会记录所有Token下已登录数量是否大于或等于采购数量,等于了则无法登录新的机器人。 Q. 不同时间采购多个季度服务,某个服务到期后,是如何下线的? 服务每天会随机踢下线超出的数量。 Q. RPA服务,数据安全如何保障? 本服务支持公有云服务SAAS/私有化部署方式,如对数据和使用场景比较敏感,建议私有化部署,常规开发建议SAAS服务即可,SAAS服务仅是路由转发,不存储用户敏感内容数据。 Q. 服务有SDK吗? 服务目前统一HTTP接口协议调用,无业务封装SDK服务,开放性与扩展性更高。 Q. 是否支持机器人收到的消息并进行回复? 支持,设置回调消息接口,就是将收到的消息推送到您设置的接口,保证接口可接收POST 且携带JSON参数的请求。 Q. 回调服务是否支持配置多个回调接口 支持,一个Token可设置一个回调接口,采购多个机器人服务,可配置多个Token。
技术资料(以下不是实现最终效果的方案,是调研了市面上常用的技术手段)
wxbot - 微信聊天机器人
适用于微信(WeChat 3.9.8.25 | 3.9.8.15 | 3.9.7.29) 可在Windows PC微信 设置 - 关于微信 - 版本信息 中获取您当前的微信版本,如果您当前的微信版本不在上述可用的版本列表中,请至下方 3、可用版本微信安装包获取 选择最新版微信重新安装使用
未经过大量测试,存在封号风险!
免责声明
本仓库发布的内容,仅用于学习研究,请勿用于非法用途和商业用途!如因此产生任何法律纠纷,均与作者无关! 无任何后门、木马,也不获取、存储任何信息,请大家在国家法律、法规和腾讯相关原则下学习研究! 不对任何下载和使用者的任何行为负责,请于下载后24小时内删除!
关于免注
因注入版本(注入DLL,功能多点)被举报了后续不再更新了,和使用方式(READNE.md)一起放在wxbot-injector目录下了 现在只更新免注版本了 (免注只是不注入DLL了,并不是真的不需要注入!)
1、运行
bin目录下wxbot-sidecar.exe,直接运行即可
wxbot-sidecar.exe (bin/wxbot-sidecar.exe)
多种情况说明:
当无微信进程在运行时会主动拉起微信(会从注册表找微信安装目录,如果是非Setup方式安装的可能拉不起来,那么请手动启动微信并使用-p参数指定pid)如微信已运行(非多开模式下)会获取当前运行中的微信进程号您也可以使用-p参数手动指定微信进程号
> .\wxbot-sidecar.exe -p 30568
> .\wxbot-sidecar.exe --help
Usage: wxbot-sidecar.exe -p [pid] [ OPTIONS ] [ VALUE ]
Options:
-p, --pid [ pid ] Specify the process number for injection
-c, --config [ path ] Specify the configuration file path
-a, --address Specify listening address (e.g. 0.0.0.0:8080)
-b, --auto-click-login Automatically click login when there is a login button
-q, --qrcode-callback If there is a QR code when WeChat is not logged in, specify the callback address for the QR code URL, using English commas as as separators (e.g. http://127.0.0.1:8081/callback,http://127.0.0.1:8082/callback)
-w, --wechat [wechat_path,optional] Ignoring the -p parameter will pull up a WeChat instance. Please use this -w parameter after lifting the multi opening restriction!
-s, --silence Enable silent mode(without popping up the console)
-m, --multi Remove WeChat multi instance restrictions (allowing multiple instances)
-v, --version Output Version Information
-h, --help Output Help Information
目前免注入版本仅支持 3.9.8.25,请务必确认版本号正确
Linux下Docker部署
在 Linux 下使用 Docker 部署 Wechat + wxbot 全部流程已经跑通了,目前构建的公共镜像测试时间不长稳定性未知,建议各位使用时先测试 构建方式在docker路径下查看README.md和Dockerfile
ENV:
WXBOT_ARGS:wxbot的运行参数,默认已经指定了-w和-b参数
WINEPREFIX:指定wine运行的目录(一些驱动文件、程序目录的存放地址),基本无需变动
# 运行
# -e 指定环境变量
# -p 指定端口映射,这里是将本地环境的8080端口映射到容器内的8080端口,可按需更改
$ docker run -itd --name wxbot -e WXBOT_ARGS="-q xxx" -p 8080:8080 registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-9-3.9.8.25
# 如果希望将微信的数据持久化出来(包括指定wxbot.json),请使用-v参数把/home/wxbot目录映射出来
$ docker run -itd --name wxbot -e WXBOT_ARGS="-q xxx" -p 8080:8080 -v xxxx:/home/wxbot registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-9-3.9.8.25
# 可能会刷一些错误日志,不用担心,不影响使用
# 查看登陆URL,可通过百度随便找个二维码在线生成工具将登陆URL转为二维码后使用手机扫码登陆
# 再次提醒,URL不是直接访问出二维码,或者手机微信访问就可以登陆,是需要百度一个二维码在线生成,将此URL生成为二维码后使用手机微信扫码登陆!
# wxbot第一次运行时需要进行一些初始化动作,时间会较久(大约3-5分钟),此命令会占用shell不断输出,5分钟内无输出也可能是正常的,等待它初始化完成后输出登陆地址即可,期间任何报错都可以忽略,只要容器没有退出运行都可以继续等待
# 二维码扫描确认登陆后也需要一段时间才会触发服务端口监听(因为微信也有一些初始化动作),期间他也会一致刷登陆URL,这是正常的,后面再次启动就不需要了
# 直到日志出现Http Server Listen 0.0.0.0:8080,那么就可以进行访问验证了
# 正常来说初始化动作不会超过五分钟(具体视你的环境配置),如果出现了login url但是没有具体的地址并且一直无输出了那么大概率挂掉了,请尝试使用docker rm -f wxbot后重新run一个
$ docker logs -f wxbot
# 如果最终日志输出报错:
Manager Init Base faild: -3
Please review the logs and provide feedback
Manager init faild: -1
那么这可能是您当前的docker版本较低(> 20.10.8),或者在docker run时添加--security-opt seccomp=unconfined参数,完整运行命令如下:
$ docker run -itd --name wxbot -e WXBOT_ARGS="-q xxx" -p 8080:8080 --security-opt seccomp=unconfined registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-9-3.9.8.25
# 如果您还是无法成功运行,那么请尝试registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-8-3.9.8.25镜像,启动命令如下:
$ docker run -itd --name wxbot -e WXBOT_ARGS="-q xxx" -p 8080:8080 registry.cn-shanghai.aliyuncs.com/jwping/wxbot:v1.10.1-8-3.9.8.25
# docker运行微信是加了自动登陆点击的,所以对于二次及以上的运行会自动触发登陆,只需要等待手机上弹出登录框即可,如果启动长时间无响应请使用下面的命令重启
$ docker restart wxbot
2、使用
如果您在使用时遇到了缺少运行库的报错 如:由于找不到 MSVCP140.dll,无法继续执行代码。重新安装程序可能会解决此问题 如果您遇到了此类问题可通过文档最下方的网盘链接中下载 微软常用运行库.exe 进行安装 或通过此链接下载最新微软常用运行库合集解决
如果您不希望在启动时弹出命令行窗口(CMD黑框框),那么您可以使用-s参数以静默方式运行!
2.1、自动登陆
目前已支持自动登陆,这里有两种情况:
之前微信已登陆过,再次启动时出现登陆按钮,如果您启动wxbot-sidecar时指定了-b参数,则会自动触发登陆,您只需在手机端确认登陆即可(请注意,当您使用-s/--silence参数进行静默运行时-b/--auto-click-login参数不生效!)之前微信未登陆过或被取消登陆,此时会渲染出二维码图片,您可以在命令行参数中指定-q参数,例如:-q http://127.0.0.1:8081/qrcode-callback 来指定一个二维码图像的回调地址,或者您也可以在配置文件中指定(参考下方的配置文件示例),当然如果您就在屏幕前,您可以直接扫码登陆
配置二维码图片回调时,命令行参数中指定的回调地址优先级要高于配置文件
2.2、多开
如果您只有一个微信实例在运行并需要注入或快速上手,那么您无需关心其它参数,直接双击运行即可如果您需要多开微信,那么请先使用wxbot-sidecar.exe -m解除微信多开限制(执行时机并不重要,您可以在任何情况下去解除多开限制)如果您已经解除了多开限制,并希望对运行中的多个微信实例进行注入:
(可选)使用-a参数指定每个实例监听的地址(格式为:ip:port),如果您的配置文件中未指定addr或地址冲突,那么此-a参数是必选项,否则会导致端口冲突(可选)使用-c参数指定第二个配置文件地址,如果您不指定一个新的配置文件地址,那么可能会导致您多个wxbot-sidecar实例共用一份配置文件(包括但不限于回调地址操作会同时影响该配置文件),推荐用法是对于多开实例每份实例使用-c参数去指定不同的配置文件运行 请注意!如果您在多开模式下希望使用wxbot-sidecar.exe拉起新的微信实例,那么您需要为每个微信新实例加上-w参数,例如:wxbot-sidecar.exe -w 或是 wxbot-sidecar.exe -w -a 0.0.0.0:8081
2.3、配置文件
配置文件支持两种方式分别是:
wxbot.json: 这是默认的配置文件(如果有的话)
Tips: 配置文件路径为 wxbot-sidecar.exe 所在的同级目录,或使用-c参数指定配置文件路径 配置文件为json格式,默认不自动创建! 配置文件优先级:-c 参数指定的配置文件 > wxbot.json > 无配置文件时的默认值
2.3.1、配置文件示例
{
"addr": "0.0.0.0:8080",
"sync-url": {
"qrcode": [
{
"timeout": 3000,
"url": "http://localhost:8081/qrlogin-callback"
}
],
"public-msg": [
{
"timeout": 3000,
"url": "http://localhost:8082/callback"
}
],
"general-msg": [
{
"timeout": 3000,
"url": "http://localhost:8081/callback"
}
]
},
"authorization": {
"enable": false,
"users": [
{
"user": "admin",
"password": "123",
"token": "token123"
},
{
"user": "user",
"password": "321",
"token": "token321"
}
]
},
"root-dir": "D:\\WeChat",
"log": {
"level": "info"
}
}
addr: wxbot服务监听地址(固定为ip:port形式)sync-url: http回调地址列表(建议通过下面的/sync-url接口修改,不要手动修改)
qrcode: 登陆界面出二维码图像时,二维码URL的回调地址
url: 回调urltimeout: 回调超时时间 general-msg: 普通类型消息回调地址
url: 回调urltimeout: 回调超时时间
Tips:这里的http://localhost:8081/callback只是一个例子,而并非必须的,如果您未启动此回调地址,那么请删除它,否则一个不可达地址将会影响后续每个回调的到达时间!
authorization: 鉴权 鉴权使用方法请您至下方 5、鉴权 了解更多
enable: 是否开启鉴权users: 用户列表(这是一个对象数组)
user: 用户名password: 密码token: 登陆后的token root-dir: 发送和获取的泛文件(图片、语音、视频、文件)存放路径,同时也会启动一个文件服务端,默认值是微信安装目录下log
level: 日志级别:分为 trace、debug、info、warn,如果您在使用中遇到了闪退、崩溃等问题,那么请将此log.level指定为trace后收集日志反馈
实际上配置文件中的所有字段都是非必填项,它们都可以独立存在,如果您不需要配置任何项,那么请不要创建它!
2.2、路由列表
响应信息 固定为JSON格式响应: {“code”: 200, data: xxxx, “message”: “xxx”}
code: 固定200message: 成功为success,失败为faild,或是其它错误提示信息data: 根据请求接口不同数据不同,无特别描述时下面的请求接口返回字段全部为该data字段的子字段
路由列表概览:
功能类
/api/checklogin - 检查登陆状态/api/userinfo - 获取登陆用户信息/api/contacts - 获取通讯录信息(wxid从这个接口获取),不建议使用,请使用下面的/api/dbcontacts/api/dbcontacts - 从数据库中获取通讯录信息(wxid从这个接口获取)/api/sendtxtmsg - 发送文本消息(好友和群聊组都可通过此接口发送,群聊组消息支持艾特)/api/sendimgmsg - 发送图片消息(支持json和form-data表单上传两种方式,json方式请将二进制数据使用base64编码后发送)/api/sendfilemsg - 发送文件消息(支持json和form-data表单上传两种方式,json方式请将二进制数据使用base64编码后发送)/api/chatroom - 获取群聊组成员列表,不建议使用,请使用下面的/api/dbchatroom/api/dbchatroom - 从数据库中获取群聊组信息和成员列表/api/accountbywxid - WXID反查微信昵称(支持好友、群聊组和群聊组内成员等),不建议使用,请使用下面的/api/dbaccountbywxid/api/dbaccountbywxid - 从数据库中通过WXID反查微信昵称(支持好友、群聊组和群聊组内成员等)/api/forwardmsg - 消息转发/api/dbs - 获取支持查询的数据库句柄/api/execsql - 通过数据库句柄执行SQL语句/api/lz4decode - 将lz4压缩的数据进行解码(请求数据需要base64)/close - 停止 wxbot-sidecar(此命令用来停止http server,并中止程序运行) 回调注册类(目前仅用来获取微信实时消息 - 同步消息接口,同时支持WebSocket和http两种方式!)
/ws/generalMsg - 注册websocket回调(支持注册多个ws通道):通用消息回调/ws/publicMsg - 注册websocket回调(支持注册多个ws通道):订阅号(公众号)消息回调/api/syncurl - http回调相关(支持注册多个http接口,注册请带上协议头:http/https,注册成功会持久化到配置文件中)
2.2.1、功能类接口
以[]中括号括起来的字段为可选字段 目前所有请求和响应字段均按大驼峰命名法规范
2.2.1.0、检查登陆状态
协议信息
GET /api/checklogin
别名
/api/checkLogin
/api/check-login
/api/check_login
响应字段
status string: 1: 登陆正常,其余非1值都为异常状态wxid string: 登陆用户wxid
2.2.1.1、登陆用户信息
协议信息
GET /api/userinfo
别名
/api/userInfo
/api/user-info
/api/user_info
响应字段
customAccount string: 微信号city string: 城市country string:国家dbKey string:数据库加密key,可解密读取数据库nickname string: 微信昵称phone string: 手机号phoneSystem string: 手机系统privateKey string:私钥profilePicture string: 头像province string:省publicKey string:公钥signature string:个性签名wxid string
2.2.1.2、通讯录
不建议使用,请使用下面的从数据库中获取通讯录接口
协议信息
GET /api/contacts
响应字段
contacts array
customAccount string: 微信号nickname string: 昵称v3 stringnote string: 备注notePinyin string: 备注拼音首字母大写notePinyinAll string: 备注拼音全pinyin string: 昵称拼音首字母大写pinyinAll string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像reserved1 stringreserved1 stringtype stringverifyFlag stringwxid string total uint64: 通讯录成员总数
2.2.1.3、从数据库中获取通讯录
协议信息
GET /api/dbcontacts
别名
/api/dbContacts
/api/db-contacts
/api/db_contacts
响应字段
contacts array
Alias string: 微信号NickName string: 昵称EncryptUserName string:v3Remark string: 备注RemarkPYInitial string: 备注拼音首字母大写RemarkQuanPin string: 备注拼音全PYInitial string: 昵称拼音首字母大写QuanPin string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像type stringUserName string:wxid其余字段请自测 total uint64: 通讯录成员总数
2.2.1.4、发送文本消息
对于群聊组消息发送支持艾特
协议信息
POST /api/sendtxtmsg
别名
/api/sendTxtMsg
/api/send-txt-msg
/api/send_txt_msg
请求字段
wxid stringcontent string:发送消息内容(如果是群聊组消息并需要发送艾特时,此content字段中需要有对应数量的@[自定义被艾特人的昵称,不得少于2个字符] [每个艾特后都需要一个空格以进行分隔(包括最后一个艾特!)],这一点很重要! 如果您不理解,请继续看下面的Tips!)[atlist] array
Tips:如果是群聊艾特消息,那么content字段中的@艾特符号数量需要和atlist中的被艾特人数组长度一致,简单来说,就是atlist中有多少个被艾特人的wxid,那么content字段中就需要有多少个艾特组合,位置随意,例如: {"wxid": "xx@chatroom", "content": "这里@11 只是@22 想告诉你@33 每个被艾特人的位置并不重要", "atlist": ["wxid_a", "wxid_b", "wxid_c"]} 每个被艾特人在content中 固定为@[至少两个字符的被艾特人名] + 一个空格! 如果是发送@所有人消息,那么请在atlist字段中仅传入一个notify@all字符串,content字段中仅包含一个@符号规范(最少两字符+一个空格), 一般建议是@所有人见名知意
响应示例
{“code”:200,“msg”:“success”}
2.2.1.5、发送图片消息
如果您发送图片失败,那么可能是权限问题,如果您的程序工作目录(wxbot-sidecar所在的目录)是在C盘,那么请尝试移动到其他分区中,例如D盘,如果还未解决,请您在github上提issue或加交流群反馈
协议信息
POST /api/sendimgmsg
别名
/api/sendImgMsg
/api/send-img-msg
/api/send_img_msg
/api/sendimagemsg
/api/sendImageMsg
/api/send-image-msg
/api/send_image_msg
支持JSON和form-data表单两种方式提交
请求头
JSON:Content-Type: application/jsonform-data表单:Content-Type: multipart/form-data
请求字段
JSON:
wxid stringpath string:图片路径(注意,这里的图片路径是bot登陆系统的路径!)image string: 图片二进制数据base64编码后字符串 (不需要加 data:image/jpeg;base64, 前缀)clear bool: 指定图片发送后是否需要删除,默认删除 (需要注意的是,图片文件保存后并没有后缀,这意味着如果您需要查看历史发送图片,那么您需要至[微信根目录]/temp自行查看判断图片格式并添加后缀) form-data表单 符合标准form-data数据格式,需要参数分别是wxid、path和image
path和image二选一即可,当path和image同时存在时,path优先
2.2.1.6、发送文件消息
如果您发送文件失败,那么可能是权限问题,如果您的程序工作目录(wxbot-sidecar所在的目录)是在C盘,那么请尝试移动到其他分区中,例如D盘,如果还未解决,请您在github上提issue或加交流群反馈
协议信息
POST /api/sendfilemsg
别名
/api/sendFileMsg
/api/send-file-msg
/api/send_file_msg
支持JSON和form-data表单两种方式提交
请求头
JSON:Content-Type: application/jsonform-data表单:Content-Type: multipart/form-data
请求字段
JSON:
wxid stringpath string:文件路径(注意,这里的文件路径是bot登陆系统的路径!)file string: 文件二进制数据base64编码后字符串filename string: 文件名(使用file字段时,此字段必填) form-data表单 符合标准form-data数据格式,需要参数分别是wxid、path和image
Tips: 当文件大小大于5M时则建议使用path文件路径的方式传参,但这并不意味着file不支持大文件发送,只是它需要更久的调用时间,可能是分钟级!path和file二选一即可,当path和file同时存在时,path优先,当使用JSON格式和file参数直接传递文件数据时filename是必填项!
path和file二选一即可,当path和file同时存在时,path优先
2.2.1.7、获取群聊组信息
不建议使用,请使用下面的从数据库中获取群聊组信息
协议信息
同时支持GET和POST
GET /api/chatroom?wxid=xxxx POST /api/chatroom
别名
/api/chatRoom
/api/chat-room
/api/chat_room
请求字段
JSON:
wxid string
响应字段
data map
wxid string:
customAccount string:微信号nickname string:昵称note string:备注pinyin string: 昵称拼音首字母大写pinyinAll string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像v3 string
2.2.1.8、从数据库中获取群聊组成员信息
协议信息
同时支持GET和POST
GET /api/dbchatroom?wxid=xxxx POST /api/dbchatroom
别名
/api/dbChatRoom
/api/db-chat-room
/api/db_chat_room
请求字段
JSON:
wxid string
响应字段
data map
Announcement string:群公告AnnouncementEditor string:群公告编辑人AnnouncementPublishTime string:群公告编辑秒级时间戳wxid string:
Alias string: 微信号NickName string: 昵称EncryptUserName string:v3Remark string: 备注RemarkPYInitial string: 备注拼音首字母大写RemarkQuanPin string: 备注拼音全PYInitial string: 昵称拼音首字母大写QuanPin string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像type stringUserName string:wxid 其余字段请自测
2.2.1.9、WXID反查信息
不建议使用,请使用下面的从数据库中通过WXID反查信息 协议信息
同时支持GET和POST
GET /api/accountbywxid?wxid=xxxx POST /api/accountbywxid
别名
/api/accountByWxid
/api/account-by-wxid
/api/account_by_wxid
请求字段
JSON:
wxid string
响应字段
customAccount string:微信号nickname string:昵称note string:备注pinyin string: 昵称拼音首字母大写pinyinAll string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像v3 string
2.2.1.10、从数据库中通过WXID反查信息
协议信息
同时支持GET和POST
GET /api/dbaccountbywxid?wxid=xxxx POST /api/dbaccountbywxid
别名
/api/dbAccountByWxid
/api/db-account-by-wxid
/api/db_account_by_wxid
请求字段
JSON:
wxid string
响应字段
Alias string: 微信号NickName string: 昵称EncryptUserName string:v3Remark string: 备注RemarkPYInitial string: 备注拼音首字母大写RemarkQuanPin string: 备注拼音全PYInitial string: 昵称拼音首字母大写QuanPin string: 昵称拼音全profilePicture string:头像profilePictureSmall string:小头像type stringUserName string:wxid其余字段请自测
2.2.1.11、转发消息
协议信息
同时支持GET和POST
GET /api/forwardmsg?wxid=xxxxxxxxxxx&msgId=xxxxxxxxxxxx POST /api/forwardmsg
别名
/api/forwardMsg
/api/forward-msg
/api/forward_msg
请求字段
这里说明一下,因为前端精度问题,有些大佬可能传递msgId字段时存在精度丢失或自动转字符串的问题,所以这里我将msgId字段设置为了同时支持uint64和string两种类型!
JSON:
wxid string:本次转发消息的接收对象msgId uint64|string:消息id(通常可以用消息回调或者websocket回调获取到,当前是消息回调中的MsgSvrID字段)
2.2.1.12、获取数据库句柄
协议信息
GET /api/dbs
响应字段
map
string: 数据库名uint64: 句柄
2.2.1.13、执行SQL语句
协议信息
同时支持GET和POST
GET /api/execsql?dbName=PublicMsg.db&sql=‘select * from PublicMsg ORDER BY localId DESC limit 1’ (这是一个实际可用的例子,前提是你收到过订阅号消息) POST /api/execsql
别名
/api/execSql
/api/exec-sql
/api/exec_sql
请求字段
JSON:
dbName string:需要执行SQL的数据库名sql string:需要执行的SQL语句
可执行的SQL例子:
PublicMsg.db
查询指定公众号的所有文章(本地已接受的) SELECT * FROM PublicMsg WHERE StrTalker=='gh_13508120ed24'
查询指定时间范围的所有订阅号文章(20230115全天的) SELECT * FROM PublicMsg WHERE CreateTime>1705248000 AND CreateTime<1705334399;
分页查询,从第21行开始,累加20条数据进行检索 SELECT * FROM PublicMsg ORDER BY localId DESC limit 20,20;
MicroMsg.db
查询通讯录所有成员(包括好友、群聊组、订阅号等) SELECT * FROM Contact
2.2.1.14、lz4数据解码
提交的数据需要经过Base64 Encode
协议信息
同时支持GET和POST
GET /api/lz4decode?compressContent=xxxxxxxxxxx POST /api/lz4decode
别名
/api/lz4Decode
/api/lz4-decode
/api/lz4_decode
请求字段
JSON:
compressContent string:经过Base64 Encode的lz4压缩数据
响应字段
content string:lz4解压缩后的数据
2.2.1.15、停止程序
协议信息
GET /close
停止 wxbot-sidecar(此命令用来停止http server,并中止程序运行),当以静默方式运行时此命令可以比较方便的用来停止程序
2.2.2、回调注册类
目前已知BUG是部分环境/微信号有登陆后微信崩溃的问题,因为我本地环境均未复现出该问题,所以修复进度较慢,但修复中… 如果您愿意提供程序日志我不胜感激
2.2.2.1、登陆二维码回调(qrcode)
响应字段
url string:登陆二维码URL(需在微信中渲染为二维码后扫码)
2.2.2.2、订阅号消息回调(public-msg)
wxid string:当前实例登陆用户的wxidtotal uint32:每次回调的消息数量data:
BytesExtra string:扩展字段BASE64后的二进制数据BytesTrans stringContent string:订阅号号XML消息CreateTime string:秒级时间戳IsSender string:是否是自己发出的消息(0:非自己发送、1:自己发送)StrTalker string:订阅号发送者微信ID(wxid)SubType string:消息类型子类,例如视频消息大类下可能存在小程序等小类的区分Type string:消息类型localId string:本地数据库ID,目前来看是一个自增IDMsgSvrID string:消息idStatusEx、FlagEx、Status、MsgServerSeq、MsgSequence、Reserved0-6、TalkerId 未知
2.2.2.3、普通消息回调(general-msg)
响应字段
wxid string:当前实例登陆用户的wxidtotal uint32:每次回调的消息数量data:
BytesExtra string:扩展字段BASE64后的二进制数据BytesTrans stringStrContent string:字符串数据,除文本消息以为大部分均为XML数据Content string:引用消息、用户转发的订阅号消息等CreateTime string:秒级时间戳
从PC登陆微信上发出的消息:标记代表的是每个消息点下发送按钮的那一刻从其它设备上发出的/收到的来自其它用户的消息:标记的是本地从服 务器接收到这一消息的时间 DisplayContent string:拍一拍,邀请入群等消息IsSender string:是否是自己发出的消息(0:非自己发送、1:自己发送)StrTalker string:消息发送者微信ID(wxid)SubType string:消息类型子类,例如视频消息大类下可能存在小程序等小类的区分Type string:消息类型localId string:本地数据库ID,目前来看是一个自增IDMsgSvrID string:消息idSender string:群聊消息发送人的wxid(仅在消息为chatroom群聊消息时存在该字段)StatusEx、FlagEx、Status、MsgServerSeq、MsgSequence、Reserved0-6、TalkerId 未知
2.2.2.1、websocket协议消息
协议信息
订阅号消息 GET ws://xxxxx/ws/publicMsg
普通消息 GET ws://xxxxx/ws/generalMsg
消息体参考回调响应字段
websocket没什么好说的,基本上第三方库都有直接可用的实现,协议升级后就是一条全双工通道,目前只用来接收同步微信的实时消息,不要发送消息到服务端,服务端不会响应。
2.2.2.2、http协议
需要你自己起一个Http Server服务用来接收微信的实时消息,你自己的Http Server启动之后通过接口注册到wxbot即可
2.2.2.2.1、注册接口
POST /api/syncurl
别名
/api/syncUrl
/api/sync-url
/api/sync_url
请求字段
url string: 你自己启动的Http Server地址路由(ip:port/[subpath])timeout int: 超时时间(当有一条新消息通过wxbot发送到你的回调地址时的最长连接等待时间)type: string
qrcode:二维码消息回调(仅存在登陆二维码时触发)public-msg:订阅号消息回调general-msg:普通消息回调
2.2.2.2.2、获取已注册接口列表
GET /api/syncurl
别名
/api/syncUrl
/api/sync-url
/api/sync_url
2.2.2.2.3、删除接口
DELETE /api/syncurl
别名
/api/syncUrl
/api/sync-url
/api/sync_url
请求字段
url: 已注册的Http Server地址(ip:port/[subpath])type: string 此版本开始同时支持msg和msg2两种回调(默认值:msg)
2.3、接口使用例子
Windows 所有powershell或者是使用cmd测试发送的例子都可能有编码问题!建议直接用程序测试!
# 发送文本
curl -Method POST -ContentType "application/json" -Body '{"wxid":"47331170911@chatroom", "content": "测试内容\nhello world!"}' http://127.0.0.1:8080/api/sendtxtmsg
# 发送艾特消息
curl -Method POST -ContentType "application/json" -Body '{"wxid":"47331170911@chatroom", "content": "测试内容\nhello world!", "atlist": ["被艾特人的wxid"]}' http://127.0.0.1:8080/api/sendtxtmsg
# 发送图片消息
curl -Method POST -ContentType "application/json" -Body '{"wxid":"47331170911@chatroom", "image": "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="}' http://127.0.0.1:8080/api/sendimgmsg
# 发送文件消息
curl -Method POST -ContentType "application/json" -Body '{"wxid":"47331170911@chatroom", "file": "aGVsbG8gd29ybGQ=", "filename": "1.txt"}' http://127.0.0.1:8080/api/sendfilemsg
# 注册普通消息回调
curl -Method POST -ContentType "application/json" -Body '{"url":"http://127.0.0.1:8011", "timeout": 3000, "type": "general-msg"}' http://127.0.0.1:8080/api/syncurl
Linux
# 获取登陆用户信息
curl 127.0.0.1:8080/api/userinfo
# 获取通讯录信息
curl 127.0.0.1:8080/api/contacts
# 发送文本消息
curl -XPOST -H "Content-Type: application/json" -d'{"wxid": "47331170911@chatroom", "content": "测试内容\nHello World"}' 127.0.0.1:8080/api/sendtxtmsg
# 发送图片消息1(使用form-data表单方式提交)
curl -XPOST -F "wxid=47331170911@chatroom" -F "image=@/home/jwping/1.jpg" 127.0.0.1:8080/api/sendimgmsg
# 发送图片消息2(使用json方式提交)
curl -XPOST -H "Content-Type: application/json" -d'{"wxid": "47331170911@chatroom", "image": "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="}' 127.0.0.1:8080/api/sendimgmsg
# 发送文件消息1(使用form-data表单方式提交)
curl -XPOST -F "wxid=47331170911@chatroom" -F "file=@/home/jwping/1.txt" 127.0.0.1:8080/api/sendfilemsg
# 发送文件消息2(使用json方式提交)
curl -XPOST -H "Content-Type: application/json" -d'{"wxid": "47331170911@chatroom", "filename": "1.txt", "file": "aGVsbG8gd29ybGQh"}' 127.0.0.1:8080/api/sendfilemsg
# 注册ws回调
# 使用任意程序websocket客户端连接127.0.0.1:8080/ws
# 注册http 普通消息回调(http协议头不能少!)
curl -XPOST -d'{"url": "http://127.0.0.1:8081/callback", "timeout": 6000, "type": "general-msg"}' 127.0.0.1:8080/api/sync-url
# 获取当前已注册的http回调
curl 127.0.0.1:8080/api/sync-url
# 删除一个已注册的http回调
curl -XDELETE -d'{"url": "http://127.0.0.1:8081/callback"}' 127.0.0.1:8080/api/sync-url
5、鉴权
当您在配置文件中开启了鉴权之后则 您后续的每个api请求都需要包含鉴权信息! 这里使用的是Http Basic Authentication,您可以先百度去了解一下它,当然,如果您不想了解也没关系,因为它真的很简单
# 假设您定义一个如下用户:
{
"user": "user2",
"password": "321",
"token": "token321"
}
那么您需要在您后续的每次请求的请求头中加上Authorization字段:Authorization: Basic base64(username:password) 例如用curl命令请求的话,它可能长这样:
curl -H "Authorization: Basic dXNlcjI6MzIx" 127.0.0.1:8080/login -v
# response:
{"code":200,"data":{"token":"token321","user":"user2"},"msg":null}
这里引入了一个新的路由/login,但我并不想将他写到上面的路由列表中,因为它真的没什么用,仅仅是在您登陆成功之后返回一个当前的登陆用户名和token 您在以后每个请求都加上Authorization: Basic dXNlcjI6MzIx这个请求头就可以了!
如果您希望使用cookie的方式,那么您可以在cookie中指定token 例如,您也可以这样做:
curl --cookie "access_token=token321" 127.0.0.1:8080/userinfo -v
如果您不想用设置请求头的方式,那么您也可以在后续的所有请求的cookie中指定access_token字段即可。 实际上cookie也是request header中的一个字段
6、wxbox、可用版本微信安装包等获取
阿里网盘: https://www.aliyundrive.com/s/4eiNnE4hp4n 提取码: rt25
百度网盘: https://pan.baidu.com/s/1cmzXe8AxYvzXWW2WTVCdxQ?pwd=l671 提取码:l671
微信逆向之朋友圈
掌握逆向的一些小技巧,及如何一步步的爬取到微信朋友圈的数据的过程。关于微信逆向的工作,可能很多小伙伴呢都干过这事,最让人头疼的就是如何快速定位一个Hook点。还有就是如何理清被混淆之后的代码。这两个点弄清楚,可能Hook你所要的东西,那就是很轻松了。我这里只是针对Android的微信7.0.3版本最新版本7.0.4 生活在这样的大数据年代,当然数据是最重要的,如果作为一个商户,你有N多个客户,那如何对这些商户进行分类,其次就是做到精准营销,然后那就是Money了。 那位对于朋友圈数据的分析会起到非常重要的作用。给每个商户打上一个Tag。
准备工作
一台root的手机 一个微信Apk : https://weixin.qq.com/cgi-bin/readtemplate?lang=zh_CN&t=page/faq/android/703/index&faq=android_703 Xpose 工具 :https://github.com/rovo89 Jadx 工具: https://github.com/skylot/jadx
以上除了手机root外,其他的工具我都附上了链接,大家直接去下载即可。对于如何root手机,作为一个Android 开发者,自行Google吧 推荐通过TWRP+SuperSu 的方式,很多机型都可以烧成功。网上很多案例。xpose 的使用这里我就不过多的赘述了,一些Api的调用而已。Jadx这个工具呢必不可少,当然你也可以使用其他的反编译工具(dex2jar,jeb,jd-gui…)用着顺手就行,我这里使用的是Jadx,啊真的很好用。
加载微信源码
以下的操作会让你加快Hook点定位
用Jadx 打开下载好的微信Apk,编译成功应该是如下页面
把编译好的项目另存为Gradle项目
用AS 打开刚刚另存的Gradle项目,AS 可以帮们建立快速索引,方便我们调试找Hook点。可能还有更好的操作,有同学知道的可以留言区交流以下
以上操作完成之后,准备工作已经大部分都完成了。 朋友圈数据库 这里我就简单介绍一下,网上也有这方面的资料,SnsMicroMsg.db这个就是保存我们朋友圈数据的数据库,SnsInfo这个表是具体内容,我们可以在/data/data/com.tencent.mm/MicroMsg/md5({mm+uin})账号目录下找到这个文件,而且也没有对数据库加密,可一直直接Navicat打开的,但是微信聊天记录数据库就是加密的,需要破解密码才能打开,密码一直没变过还是通过{IMEI+UIN}md5即可,回到主题,但是虽然你可以拿到朋友圈数据库,但是你发现并没有什么卵用,里面的数据全部加密了,完全摸不着头脑。这里大家可以看看这个数据库文件。除了能看到userName 和createTime 有点用,其他的字段真是看不到头绪
接下来注意观察第二张图片,content,attrBuf,这二个字段里面全是BLOB格式的,可以发现,小老弟把数据藏起来了啊。那难道我们就没有办法了吗!当然还是可以拿的到的,那就是通过微信源码查看了,我们接下来的工作就是,看微信是如何拿到这个BLOB,如何进行解析的。我们也通过他的方式进行解析不就得了吗。接下来进入主题。 Hook朋友圈Activity 我这里Hook点是个人朋友圈入口,通过点击通讯录,进入个人的朋友圈页面,然后找到这个Activity是哪一个Activity,然后查看这个页面的源码。目前到现在为止,还没有用到Xpose 这个工具,那么我们如何知道这个Activity是哪个呢,其实Android系统给我们提供了一个dumpsys的工具,根据包名可以获取到当前是哪个Activity,我们只需要adb shell 登进去
点击进入某个人的盆友圈,然后调用一下代码就可以获取当前是哪个activity了
dumpsys activity |grep -i com.tencent.mm
打开微信个人朋友圈页面执行上述代码之后即可获取当前页面,这时候可以在terminal里面看到如下
com.tencent.mm/.plugin.sns.ui.SnsUserUI
到此为止,我们已经知道了个人朋友圈页面在哪里了。接下来我们去刚刚AS打开的微信项目里面找到这个SnsUserUI Activity了,打开页面可以发现很多代码已经混淆的很难读懂了,什么a.a.a,b.c.da这样的包名已经方法名。但是我们这时候不要慌张。接下来打开手机,我们可以通过微信这个页面的UI看到,这是一个list,那肯定不是listview就是recyclerview了。这是后打开AS找到SnsUserUI这个类,然后倒开他的structure目录
可以发现里面有个方法initView 是不是很熟悉,我们经常写代码也会这样写,那么我们这就点进去看一下, 这里就不粘贴很多代码。有兴趣可以自行反编译看看
public final void initView() {
this.qXD = (RelativeLayout) findViewById(f.sns_user_year_tip_layout);
this.qXE = (TextView) findViewById(f.sns_user_year_tip);
this.qXD.post(new Runnable() {
public final void run() {
LayoutParams layoutParams = new LayoutParams(-1, -2);
layoutParams.topMargin = x.aj(SnsUserUI.this) + SnsUserUI.this.getResources().getDimensionPixelSize(i.d.ActionBarHeight);
SnsUserUI.this.qXD.setLayoutParams(layoutParams);
}
});
this.qXz = new as(this, new a() {
public final void fc(int i, int i2) {
super.fc(i, i2);
}
}, this.hMy, new as.c() {
});
this.qXA.naj.setAdapter(this.qXz);
this.qXA.naj.setOnItemClickListener(new OnItemClickListener() {
public final void onItemClick(AdapterView> adapterView, View view, int i, long j) {
}
});
打开观察之后,发现这里面有个setAdapter的地方,对的!肯定数据就在这个Adapter里面,因为我们平时写list 渲染的时候数据都是通过adapter 渲染到list 上的,我们继续点进去看看这个adapter 是如何写的。
朋友圈Adapter深入 我们通过上述的方法已经找到了Adapter了,我们点击(this.qXz)这个字段发现他的类名是as,点击进去发现,果然没错。
public final class as extends BaseAdapter {
private Activity coM;
boolean cog = false;
private String country;
List
String lnO = "";
private String ngt = "";
Map
Map
int qBe = 0;
int qBf = 0;
String qHI = "";
private bd qKW = null;
private az qQo;
Map
private f qQq;
boolean qQr = false;
at qQs;
private c qQt;
int qQu = BaseClientBuilder.API_PRIORITY_OTHER;
int qQv = 0;
private long qQw = 0;
private long qQx = 0;
int qQy = 0;
protected OnClickListener qQz = new OnClickListener() {
public final void onClick(View view) {
if (view.getTag() instanceof TimeLineObject) {
TimeLineObject timeLineObject = (TimeLineObject) view.getTag();
if (as.Yp(timeLineObject.Id)) {
h.ptS.X(10231, "1");
com.tencent.mm.av.a.agc();
} else {
h.ptS.X(10090, "1,0");
if (!(com.tencent.mm.q.a.bN(as.this.coM) || com.tencent.mm.q.a.bL(as.this.coM))) {
com.tencent.mm.av.e a = g.a(af.getAccPath(), timeLineObject, 8);
a.fuR = as.this.userName;
com.tencent.mm.av.a.b(a);
}
}
as.this.notifyDataSetChanged();
}
........省略很多代码........
那我们接下来怎么找呢,Adapter已经拿到了,难道还是一点点翻吗?当然不是了,想想我们日常写listview的Adapter时候,是不是在getView的时候进行给view赋值的操作,这时候微信也一样,我们同样打开as这个类的structure目录
从图中可以发a这个方法嫌疑很大,里面有各种view
private void a(int i, QFadeImageView qFadeImageView, TextView textView, TextView textView2, TextView textView3, TextView textView4, int i2, d dVar, int i3) {
n nVar = (n) getItem(i);
TimeLineObject cmi = nVar.cmi();
bys q = aj.q(nVar);
Object obj = null;
if (q != null && (((q.vUS & 2) == 2 && q.wnx != null) || ((q.vUS & 4) == 4 && q.vTG != null))) {
obj = 1;
}
if (!(!this.cog || q == null || obj == null || this.userName == null || !this.userName.equals(nVar.field_userName))) {
textView3.setBackgroundResource(com.tencent.mm.plugin.sns.i.e.personactivity_sharephoto_icon);
textView3.setVisibility(0);
}
........省略很多代码........
我们点进去可以看到,果然如同我们所想一样,第一行就暴露了, n nVar = (n) getItem(i); 可以发现这个n类就是每个item的数据源,而且往下看一行,这个类名也很有嫌疑TimeLineObject,而且是通过n 调用cmi方法返回的,那会不会是数据库里面的那个BLOB字段呢。容我们点进去看看
Map
........省略很多代码........
public final TimeLineObject cmi() {
if (this.field_content == null) {
return e.ahM();
}
TimeLineObject timeLineObject;
if (this.qzT == null) {
this.qzT = g.u(this.field_content) + g.u(this.field_attrBuf);
}
if (qAb.containsKey(this.qzT)) {
timeLineObject = (TimeLineObject) qAb.get(this.qzT);
if (timeLineObject != null) {
return timeLineObject;
}
}
try {
timeLineObject = (TimeLineObject) new TimeLineObject().parseFrom(this.field_content);
qAb.put(this.qzT, timeLineObject);
return timeLineObject;
} catch (Exception e) {
ab.e("MicroMsg.SnsInfo", "error get snsinfo timeline!");
return e.ahM();
}
}
这时候发现了不可思议的东西 field_content 和 field_attrBuf 这两个字段,这个不就是数据库里面定义的content和attrbuf字段吗。原来是通过这样的方式转化的。继续往下看,可以发现如果 ’ qAb.get(this.qzT) ’ 拿不到TimeLineObject的话,就会自己new 一个然后存储到这个Map集合中,做缓存作用,那我们是不是可以通过这种方式呢拿到这个TimeLineObject,当然是可以的。
解码朋友圈BLOB字段 通过上面我们已经知道了如何解析朋友圈数据库content 字段了,通过TimeLineObject的parseFrom方法进行转化。但是当我们点到TimeLineObject这个类里面你会发现,卧槽,怎么这样。
public class TimeLineObject extends a {
public String Id;
public int dhE;
public int eRm;
public String hPC;
public String jfn;
public int ozl;
public String qEy;
public String qXr;
public av qiN;
public csw qiP;
public String uzJ;
public int vTa;
public int wsA;
public String wsB;
public ccr wsC;
public cqv wsD;
public int wsE;
public String wsu;
public axc wsv;
public du wsw;
public ta wsx;
public String wsy;
public int wsz;
可以发现里面嵌套了很多的类。这是我时候我们怎么做呢。我也没有很好的办法,然后就通过一个类一个类的点开,然后打印它里面是String字段,这里应该来个表情捂脸,有好方法的同学们可以留言区交流,但是当我打印到了wsu这个字段的时候发现,可以拿得到我们发朋友圈时的标题了。瞬间感觉到了轻松。但是这只是一个很小的进步,我们要拿的可是朋友圈图片视频评论点赞所有内容啊。 获取朋友圈信息源具体内容 那么如何获取到图片视频等信息呢。那么我们还是要回到adapter 这个类里面。在他的a方法中有个构造参数QFadeImageView看到ImageView 感觉离获取图片地址不远了。那么我们继续观察这个方法。
private void a(int i, QFadeImageView qFadeImageView, TextView textView, TextView textView2, TextView textView3, TextView textView4, int i2, d dVar, int i3) {
n nVar = (n) getItem(i);
TimeLineObject cmi = nVar.cmi();
bys q = aj.q(nVar);
Object obj = null;
if (q != null && (((q.vUS & 2) == 2 && q.wnx != null) || ((q.vUS & 4) == 4 && q.vTG != null))) {
obj = 1;
}
........省略很多代码........
if (cmi.wsx.vqt == 1) {
qFadeImageView.setVisibility(0);
af.cjr().a(cmi.wsx.vqu, (View) qFadeImageView, this.coM.hashCode(), com.tencent.mm.plugin.sns.model.g.a.IMG_SCENE_SNSSUSER, azVar);
} else if (cmi.wsx.vqt == 2) {
textView4.setText(bp.bb(cmi.wsx.Desc, ""));
textView4.setVisibility(0);
} else if (cmi.wsx.vqt == 21) {
nVar.cmA();
boolean z = true;
if (this.cog) {
z = true;
} else if (m.a(nVar, q)) {
z = false;
}
qFadeImageView.setVisibility(0);
af.cjr().a(cmi.wsx.vqu, (View) qFadeImageView, this.coM.hashCode(), com.tencent.mm.plugin.sns.model.g.a.IMG_SCENE_SNSSUSER, azVar, z);
}
........省略很多代码........
从上面的代码中我们可以看得到,微信这边调用了这个方法把 af.cjr().a(xxxxx)把Imageview 传入了进入,点击查看了其他的参数只有cmi.wsx.vqu这个参数有用。可以发现他调用了TimeLineObject里面ta这个类里面的集合vqu字段。
public final class ta extends a {
public String Desc;
public String Title;
public String Url;
public int vqt;
public LinkedList
public int vqv;
public String vqw;
public ayd vqx;
先不管调用了imageview 这个方法干了什么,我们先把这个集合里面的东西给打印出来。
azc.toString{id:13055580620160049319 Desc:黄昏 Title: Url:http://mmsns.qpic.cn/mmsns/kEgG3ynkRxponsiaCyzhl9Gniaz7GdWLujZdSMV4kmlME6fia07m577MQ3OU9kMKibjAIiaMc7MWHKF0/0 ckO:null qDg: vSY:http://mmsns.qpic.cn/mmsns/kEgG3ynkRxponsiaCyzhl9Gniaz7GdWLujZdSMV4kmlME6fia07m577MQ3OU9kMKibjAIiaMc7MWHKF0/150 vTc: vTf: vTh: vTi: vTj: vTm:f814a6351db8cd3ef118e14e6ff70b80 vTn:WSEN6qDsKwV8A02w3onOGQYfxnkibdqSOkmHhZGNB4DFJ9qdBeATTF8UiaDA1go3GLryav2ukPJK06SOFjchiaqJA vTp:14604729124651202068 vTq:WSEN6qDsKwV8A02w3onOGQYfxnkibdqSOkmHhZGNB4DFJ9qdBeATTF8UiaDA1go3GLwHGCkbxWxDWW5dsMhLsBUg vTs:14604729124651202068 vTt:}
不出我们所料,里面果然有我们需要的东西,而且把Desc,url都给了我们,通过我的测试发现图片的url并不能打开。但是视频链接的url是可以打开的。是不是很happy。这时候我们已经拿到了视频源和分享的链接源,但是如何拿到图片源呢。那我们继续查看源码,发现点击刚刚给上述调用了这个集合的方法里面并没有什么东西,都是一些赋值的操作。没有获取具体图片源信息的位置。 这时候我是这样操作的,因为这个获取到的Url虽然我们解析不了,但是我们可以点击查看Url的引用,看哪里有着对这个Url字段的引用,微信内部是如何解析的 当你点击开的时候会发现并没有什么用处,见下图
引用的地方太多了,根本不知道如何下手。这时候又会一头雾水不知道如何进行下一步。那么我们只能回到起点,再次寻找下一个hook点。 进入朋友圈详情二次Hook 既然上一个页面我们拿不到图片的数据,那我们就深入进入朋友圈具体内容页面,然后进行二次Hook,获取到朋友圈具体图片内容。我们还是以同样的方法进行,hook,打开此页面然后通过 dumpsys 获取当前的activity,进入这个activity查看源码下手找到图片的具体位置。
通过代码查看到这是一个com.tencent.mm.plugin.sns.ui.SnsGalleryUI,顾名思义,朋友圈相册页面。那么我们点进去看看具体写了些什么东西
public class SnsGalleryUI extends SnsBaseGalleryUI implements a {
private int qKn = 0;
private String userName = "";
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
getWindow().addFlags(128);
wS(this.mController.xyi.getResources().getColor(c.dark_actionbar_color));
LV(this.mController.xyi.getResources().getColor(c.dark_actionbar_color));
initView();
}
........省略很多代码........
并没有什么东西可看的。没有具体的内容,我们进入父类SnsBaseGalleryUI看看做了些什么进入看了一下,发现方法体也没有什么东西,但是一个字段引起了我的注意
public abstract class SnsBaseGalleryUI extends MMActivity implements a {
private boolean jop = true;
private LinearLayout qKf;
r qKg;
private LinearLayout qKh;
s qKi;
private boolean qKj = true;
private TextView qKk = null;
protected SnsInfoFlip qKl;
protected Button qKm;
........省略很多代码........
我们从上面的字段可以猜到哪一个是引起了我的注意,很明显那就是SnsInfoFlip这个类。继续点击去看看里面写了些什么内容。据我猜测这应该也是个adapter,viewpager的adapter,通过structure目录可以发现里面有个getView的方法,但是反编译并没有完全把smail 内容转换成java 类型,看着比较费劲,那我们继续往下寻找,这时候你会有惊喜
可以看到这个函数里面参数是azc记忆力好的小伙伴应该还记得,前面所说的,azc这个类里面包含着url,这时候找到了用的地方了。把代码贴上大家可以看一下
private void a(azc azc, int i, String str) {
String str2;
long j = 0;
if (this.qNm != null && (this.qNm instanceof MMGestureGallery)) {
float f;
float f2;
float f3;
if (azc.vTb != null) {
f = azc.vTb.vTP;
f2 = azc.vTb.vTO;
} else {
f = 0.0f;
f2 = 0.0f;
}
if (f <= 0.0f || r5 <= 0.0f) {
if (azc.Id.startsWith("Locall_path")) {
str2 = an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.m(azc);
} else {
str2 = an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.d(azc);
}
Options akG = com.tencent.mm.sdk.platformtools.d.akG(str2);
........省略很多代码........
上面的字段local_path,博主感觉找到了那个点,开始hook这个method an.fQ(af.getAccSnsPath(), azc.Id) + com.tencent.mm.plugin.sns.data.i.m(azc);,surprise这个方法返回的值就是朋友圈图片的本地路径。打印下来是这样的路径
/storage/emulated/0/tencent/MicroMsg/cd1c67e86728a83c6079e2b48ia/sns/1/4/snst_13069507190820253764
//这个路径通过adb pull 出来,就是一张图片
通过以上的分析,我们已经定位到了哪些类和哪些方法可以帮助我们获取到朋友圈的数据。
接下来我们要做的事爬取朋友圈数据,这里两种方式爬取数据
xpose 这种方式是最简单粗暴的,hook微信的内部方法
首先通过sqlite拿到SnsMicroMsg.db 然后query SnsInfo这个表里面的数据content 通过XposedHelpers 实例化TimeLineObject 调用TimeLineObject的parseFrom方法(可获取朋友圈标题) 然后获取TimeLineObject里面的ta类,获取到集合azc(视频链接可直接通过这个类获取) 然后循环这个集合,通过SnsInfoFlip里面的a方法获取到thumb的地址。
classloader
这种方式呢,也是可行的,只需要手机root即可不需要xpose框架
首先把当前微信目录下的SnsMicroMsg这个数据库导出到Sdcard中 然后一样通过sqlite打开数据库,query SnsInfo table 接着DexClassLoader把微信apkloader起来,同时把我们上诉介绍到的类都给load进去。 然后通过反射的方式执行第一种xpose 方式也行。
通过以上两种方式皆可完成爬朋友圈数据功能,下面抛个爬取数据成功的页面。
iOS逆向微信朋友圈之获取小视频地址
在逆向的过程中,大家拿微信练手占绝大一部分,一般实现的功能有将朋友圈小视频保存到本地(现在的微信原生版已经有了这个功能)或者转发朋友圈等功能。
网上千篇一律其实本质都教你怎么一步一步的拿到WCDataItem,进而拿到小视频的地址。这里说的就是以另外一种非常简单的方法去获取。 获取小视频视图名字 我这里首先是通过Xcode的Debug View Hierarchy得到到小视频视图名字WCTLContentItemTemplateVideo,(有的教程是WCContentItemViewTemplateNewSigh,我这里的微信版本是6.5.21比较新,所以旧的版本有可能是这个名字) 定位小视频长按事件 WCTLContentItemTemplateVideo通过class-dump处理的.h文件中可以找到几个长按方法,一个一个断点测试可以知道- (void)onLongTouch就是长按事件。 打断点验证:
br s -a 0x000000000259c000+0x000000010261092c
0x000000000259c000通过image list -o -f WeChat获取 0x000000010261092c通过Hopper获取到
做到这里与网上的基本类似。只是试图不一样而已。接下来就是重点了。 找到WCDataItem 既然WCTLContentItemTemplateVideo这个视图就是显示小视频的,所以肯定会有数据源的。查看这个视图看了一下没有什么有价值的类。不过再去观看的时候会发现它是继承于WCContentItemBaseView,到这个类观察一下。
看到这个大家则会豁然开朗了。
po [[[[[$x0 oDataItem]contentObj]mediaList]lastObject]dataUrl
通过如上命令可以验证出这个就是我们要找的小视频的地址
接来怎么做相信大家肯定知道了吧。
逆向分析技术在2025年持续演进,尤其在应对新型加固技术、跨平台应用(如鸿蒙APP)及单文件打包(如.NET单文件EXE)方面有显著突破。以下分技术领域和工具类型进行系统梳理:
🔍 一、APP逆向分析技术与工具
1. 静态分析技术
鸿蒙APP解析
HAP结构解压:鸿蒙应用包(HAP)本质为ZIP格式,需解压获取.abc字节码文件(方舟编译器生成)和资源配置文件(module.json)。字节码反编译:方舟字节码(.abc)需专用工具转换为可读代码:
abc-decompiler:生成近似JavaScript的伪代码,提升业务逻辑可读性。ABCDE工具包:解析类/方法信息,支持反汇编方舟指令(需JDK17+)。华为DevEco Studio内置工具:ark_disasm.exe反汇编字节码为低级指令。 资源解析:使用HAP查看器提取资源配置(如布局、字符串映射)。 Android/iOS通用技术
加固识别与脱壳:
Apktool:解包APK,处理资源文件。Jadx:将Dex转为Java源码,支持图形化界面。Ratel:内置免Root脱壳机,支持指令级Dump(尤其应对VMP混淆)。
2. 动态分析技术
敏感API监控
Camille:基于Frida的动态检测工具,自动化记录APP对系统API(如位置、相机)的调用,支持生成Excel报告。
定制化:通过修改script.js添加Hook规则。链接:GitHub - Camille Ratel:免Root环境下的Hook框架,支持设备指纹对抗、热修复及多开分身,兼容Android 5.0–11。
链接:Ratel文档 调试与注入
Frida:跨平台动态代码插桩,支持JS脚本注入(如绕过SSL Pinning)。
典型流程:Push frida-server至设备 → Python脚本控制Hook逻辑。 Xposed模块:针对系统级Hook,如JustTrustMe(禁用证书校验)。
⚙️ 二、EXE逆向分析技术与工具
1. 单文件EXE处理
.NET单文件解包:
dnSpyEx:专项支持.NET单文件发布格式,解决嵌入式程序集提取、内存加载及元数据解析问题。
实现原理:解析文件头 → 定位内嵌程序集 → 内存重建结构 → 标准反编译。链接:dnSpyEx GitHub
2. 通用二进制分析
反汇编与反编译
Ghidra(NSA开源):
支持多平台(Win/Linux/macOS),集成反汇编、伪代码生成、脚本扩展(Python/Java)。特色:协作逆向工程(多人共享项目)、插件生态(如PDB符号加载)。链接:Ghidra官网 Cutter:基于Rizin引擎的GUI工具,集成Ghidra反编译器,支持二进制补丁和仿真调试。
链接:Cutter下载 动态调试
x64dbg:开源x86/x64调试器,支持插件扩展(如SharpOD反反调试、Scylla脱壳)。
链接:x64dbg GitHub
🧰 三、2025年主流开源工具汇总
工具名称类型简介链接Ghidra多平台反编译套件NSA开源,支持协作分析与脚本扩展官网Cutter二进制分析GUI集成Rizin引擎+Ghidra反编译,支持图形化流程图与Python脚本下载页dnSpyEx.NET反编译器专项处理单文件EXE,支持内存重建程序集GitHubCamilleAndroid动态监控基于Frida的API行为记录工具,输出Excel报告GitHubRatelAndroid沙箱免Root Hook框架,支持脱壳/多开/设备指纹对抗文档ABCDE鸿蒙字节码分析反编译方舟.abc文件,提取类与方法信息GitHubx64dbgWindows调试器插件生态丰富(如Scylla脱壳、字符串搜索)GitHub
⚠️ 四、技术挑战与应对建议
加固与混淆
问题:VMP(虚拟化保护)、代码扁平化加剧静态分析难度。方案:结合动态调试(Frida Hook关键解密函数)+ 模拟执行(Unicorn引擎)。 跨平台适配
鸿蒙方舟字节码可读性低 ➜ 使用abc-decompiler + 官方ISA文档对照。.NET单文件EXE ➜ dnSpyEx内存加载能力优先于传统ILSpy。 法律与风控
仅限授权测试,避免逆向金融/隐私类APP(如Ratel明确要求合规使用)。
💎 总结建议
移动端APP:优先组合 Ratel(动态Hook) + ABCDE(静态鸿蒙分析) + Camille(API监控)。Windows EXE:Ghidra(深度反编译) + x64dbg(动态调试) 覆盖多数场景。持续关注工具更新(如Ghidra插件库、Ratel开源进程),以应对新型保护技术。
部分工具需基础编程能力(Python/JS)定制脚本,复杂场景建议结合IDA Pro(闭源)增强深度分析能力。