Frida爬虫分析流程 您所在的位置:网站首页 微信视频号流量分析 Frida爬虫分析流程

Frida爬虫分析流程

2024-07-02 15:08| 来源: 网络整理| 查看: 265

前言

微信的通信协议没有使用传统的https,而是采用 mmtls 和 quic 协议结合的方案(可能),导致常用的抓包方案完全无效。因此我们考虑使用逆向 hook 的方式,对微信视频号的数据进行获取。

Frida 是目前几乎最好跨平台hook工具,深受广大牢友的喜爱。因此我们考虑用这个工具来进行 hook 。

提前声明,以下操作有被封号的风险,各位看官可以尽量用小号操作。

准备准备一个解锁了 bootloader 、刷了 TWRP 并安装了 Magisk 的手机。(当然,也有无需root权限的方法,但是用起来会不方便,还是建议 root )准备好 adb 环境。参考 FRIDA 安装 frida 用于 hook。并最好把官网的 Tutorials 看下。准备 Pycharm 作为开发环境。准备好 wechat.apk 。参考 JADX 安装好 jadx 用于代码静态分析。思路

Frida 爬虫的思路如下:

利用 adb 的 dumpsys 工具定位到我们关心的 Activity 页。利用 jadx 的静态分析工具在代码中定位到解密后的后的数据对象。利用 frida 的 hook 能力重写数据对象的构造、拷贝等关键方法,提取出入参出参等。将提取到的数据序列化成json,并持久化。流程启动 frida-server

首先需要在 Magisk 商店中找到 MagiskFrida 插件。这个插件会在手机启动时以高权限启动 frida-server 服务器用于后续注入 hook 代码。

如果一不小心 frida-server 跪了,只需要重启手机即可。

定位Activity

首先我们需要大概了解我们关注的页面的一些信息,方便我们后续定位代码。因此我们先打开感兴趣的页面(我这里是微信视频号的 tab),并执行 dumpsys 命令。

这样我们知道了,这个页面对应的是 FinderHomeUI 这个 activity。

定位数据对象

打开 jadx-gui ,定位到 FinderHomeUI 这个类。(可能loading一段时间,如果报OOM,则需要 通过 $ mdfind jadx-gui 找到启动脚本,并修改 JVM 参数)。

简单的四下观望,就可以找一个叫 FeedData 的类,也找到类这个类的一个类似 Builder 模式的静态内部类。

看起来这个 i 方法大概就是构造 FeedData 这个类的方法了,因此我们可以考虑下 hook 这个 i 方法。

提取重要参数

找到了上面的 com.tencent.mm.plugin.finder.storage.FeedData$a  对象,我们就可以简单编写一个hook脚本看看。

代码语言:javascript复制# -*- coding: UTF-8 -*- import frida import sys def on_message(message, data): print(message) jscode = """ Java.perform(function () { var a = Java.use('com.tencent.mm.plugin.finder.storage.FeedData$a'); var i = a.i; i.implementation = function (finderItem) { var res = i.call(this, finderItem); try{ send(JSON.stringify(res)) }catch (e){ console.log('Error: ' + e);//自己的逻辑要做好catch防止脚本有问题导致app崩溃。 } return res;//注意保证函数输出不变。 }; }); """ process = frida.get_usb_device().attach('com.tencent.mm') script = process.create_script(jscode) script.on('message', on_message) print('[*] Running Hook') script.load() sys.stdin.read()

执行这个脚本,并滑动一下可以看到如下输入:

显然,这里的 payload 并没有正确的被序列化,因此我们需要再做一个用序列化工具。

数据序列化输出

由于安卓自带的 org.json.JSONObject 不支持json序列化,而 Javascript 的方法也无法序列化 java 对象。因此我们需要自己引入一个java包用于序列化,这里我选用无脑的fastjson。

首先需要下载fastjson的jar包,我在本地的maven仓库中找到了: /Users/myths/.gradle/caches/modules-2/files-2.1/com.alibaba/fastjson/1.2.69/6cb063f1d527ff65bdbb9ea74888a5ffc3f92197/fastjson-1.2.69.jar 。然后利用 adb 的 build-tools 中的 dx 工具将 jar 包重新打包成 dex 包:$ /Users/myths/Library/Android/sdk/build-tools/26.0.2/dx --dex --output=fastjson.dex fastjson.jar 。将上述生成的 dex 包 push 到手机中,例如 /data/local/tmp/fastjson.dex  下。更改下脚本,再滑动下页面:代码语言:javascript复制# -*- coding: UTF-8 -*- import frida import sys def on_message(message, data): print(message['payload']) jscode = """ Java.perform(function () { var a = Java.use('com.tencent.mm.plugin.finder.storage.FeedData$a'); Java.openClassFile('/data/local/tmp/fastjson.dex').load(); var JSONObject = Java.use('com.alibaba.fastjson.JSONObject') var i = a.i; i.implementation = function (finderItem) { var res = i.call(this, finderItem); try{ send(JSONObject.toJSONString(res)); }catch (e){ console.log('Error: ' + e); } return res; }; }); """ process = frida.get_usb_device().attach('com.tencent.mm') script = process.create_script(jscode) script.on('message', on_message) print('[*] Running Hook') script.load() sys.stdin.read()

得到的 json 如下:

代码语言:javascript复制{ "commentCount": 62, "description": "人心换人心,谁都有底线!更多情感内容点击关注@疗伤情感 #晏子情感", "expectId": -4877419130498574272, "feedId": -4877419130498574272, "hasBgmInfo": false, "id": -4877419130498574272, "likeCount": 2951, "liveId": 0, "liveStatus": 0, "localId": 0, "longVideo": false, "mediaList": [ { "NMD": false, "NMq": 0, "NMt": false, "NMv": 28000, "NMw": "http://wxapp.tc.qq.com/251/20350/stodownload?encfilekey=RBfjicXSHKCOONJnTbRmmlD8cOQPXE48ibNoPibrzxbICjN0mdDNRj71nM2TJfVYGhIxX0WCMf74biaftFqLW2zGtdmXTJ8wibeesB7n8Ntyu5uOic8136mUibM44fnge8amjDu6BLmlSE59icicdjIrI7KtpP8FxXibG6LwzicQMlmaVaAicD0&adaptivelytrans=0&bizid=1023&dotrans=0&hy=SH&idx=1&m=5190cada35800678ed0b1f917a2a32b5", "NMx": "&token=x5Y29zUxcibDjE9JYkmdS0shbZ7djRmsC99U0UibtNT1u9hlAxSyM01icQZXHkptzicv", "bitrate": 0, "coverUrl": "http://wxapp.tc.qq.com/251/20304/stodownload?filekey=30350201010421301f020200fb040253480410d8869ba74f63ba490ac4069f994280f202030180d8040d00000004627466730000000131&storeid=323032313034303531303235343030303064316634353761356264386134653730353566363430303030303066623030303034663530&adaptivelytrans=0&bizid=1023&dotrans=0&hy=SH&m=d8869ba74f63ba490ac4069f994280f2", "decodeKey": "2065249527", "fileSize": 18284035, "full_bitrate": 0, "full_file_size": 0, "full_height": 0, "full_width": 0, "height": 1264, "hot_flag": 0, "includeUnKnownField": false, "md5sum": "f9f9eceb-6982-4e4d-bfa6-8db01fa9b522", "mediaId": "a6b5fac7d510c532a4376934a31015a4", "mediaType": 4, "spec": [ { "MZJ": 3141665, "Nbp": 637, "efu": "xV0", "includeUnKnownField": true, "vKg": "h264" }, { "MZJ": 1646534, "Nbp": 345, "efu": "xV2", "includeUnKnownField": true, "vKg": "h265" }, { "MZJ": 1037647, "Nbp": 226, "efu": "xV4", "includeUnKnownField": true, "vKg": "h265" }, { "MZJ": 472808, "Nbp": 109, "efu": "xV8", "includeUnKnownField": true, "vKg": "h265" }, { "MZJ": 418280, "Nbp": 97, "efu": "xV9", "includeUnKnownField": true, "vKg": "h264" }, { "MZJ": 295747, "Nbp": 66, "efu": "xV10", "includeUnKnownField": true, "vKg": "h265" } ], "thumbUrl": "http://wxapp.tc.qq.com/251/20304/stodownload?encfilekey=RBfjicXSHKCOONJnTbRmmlD8cOQPXE48ib0TrgC9GMRrlchGCNdXCyD2Pu6YbIWudBh6BngIDXS3M8Y18doicwuaXmAiblJJG5s2ib1XR3KMredUlbax6ZQvhQ77Ntoekw0O4VfpbFuHrhjIyEDd78AKe5GGybePkVA1jP75HyKHEyNc&adaptivelytrans=0&bizid=1023&dotrans=0&hy=SH&idx=1&m=d8869ba74f63ba490ac4069f994280f2", "thumb_url_token": "&token=x5Y29zUxcibCadRELU5qibEtIicbNZqQqzxGicvUUexAbqribwZDAdDicOa5koiawnrKUtV", "url": "http://wxapp.tc.qq.com/251/20302/stodownload?encfilekey=G83YYE2iciaib491UK8yGibLXOdhNpDoPpG748uNIa5DNuyuonSofEYDt1yf8eDoibNty4U8UXvSG2micv4HaEUcErdibfTOiaKKalN8FrUibibrfVqnPOh8sZFWl5oDALZajdFJsTg7Sqd4bPIyWib5CehDW4NbxzzdLUpoDvYBVjDkfp9C7Q&adaptivelytrans=0&bizid=1023&dotrans=906&hy=SH&idx=1&m=6b3f33e50bfc1c5c5f6f6c14e06b7d03&scene=0", "url_token": "&token=AxricY7RBHdWhPYjkduXw4angAXxhu8UMIxGebhCliaYtTT7dCtwIxRibXyGodLxZxcPJYzq9CN5dU", "videoDuration": 28, "width": 1080 } ], "mediaType": 4, "nickName": "疗伤情感", "onlineNum": 0, "rvFeedList": [], "sessionBuffer": "eyJzZXNzaW9uX2lkIjoic2lkXzIzNjY4ODU5NDVfMTYxNzc4MDIwOTk3NzYzNl8xNDk3MjAwODg4IiwicmVjb21tZW5kX3R5cGUiOjMsInJlY29tbWVuZF9zeXN0ZW0iOjIsInJlY29tbWVuZF93b3JkaW5nIjoiIiwiY3VyX2xpa2VfY291bnQiOjI5NTEsImN1cl9jb21tZW50X2NvdW50Ijo2MiwicmVjYWxsX3R5cGVzIjpbMTAxMTM1XSwiZGVsaXZlcnlfc2NlbmUiOjEzLCJkZWxpdmVyeV90aW1lIjoxNjE3NzgwMjEwLCJzZXRfY29uZGl0aW9uX2ZsYWciOjIsInRvdGFsX2ZyaWVuZF9saWtlX2NvdW50IjowLCJuZXdfZnJpZW5kX2xpa2VfY291bnQiOjAsInJlY2FsbF9pbmRleCI6WzBdLCJ0YWdfaWQiOiIwOyIsInJlcXVlc3RfaWQiOjE2MTc3ODAyMDg4MTc5MTMsIm1lZGlhX3R5cGUiOjQsInZpZF9sZW4iOjI4LCJjcmVhdGVfdGltZSI6MTYxNzU4OTU4NiwidGFiX3R5cGUiOjQsInJlY2FsbF9pbmZvIjpbeyJyZWNhbGxfdHlwZSI6MTAxMTM1LCJyZWNhbGxfc2NvcmUiOjAuNzI2MjMyOTQ1OTE5LCJyZWNhbGxfaW5kZXgiOjAsInJlcG9ydF9pbmZvIjoiNDA2XzEwMzVfMF8wXzEifV0sInJhbmtfc2NvcmUiOjEwNC40NzExNDU2Mywic2VjcmV0ZV9kYXRhIjoiQmdBQUFmMmliZTJFMXIrRFRHc2gwbzB6RGJVbnpvTkUwZDZncjliOVdKdyttakM2NkhnM3VXY0phOTg9IiwidGFiX3Nlc3Npb25faWQiOjE2MTc3ODAyMDg5MjE3ODQsImZyaWVuZF9saWtlZF9saXN0IjoiIiwiZGV2aWNlX3R5cGVfaWQiOjIsImRldmljZV9wbGF0Zm9ybSI6IlJlZG1pIDYiLCJkb3dubG9hZF9zcGVlZF9rYnBzIjoxMzE1OTUsIm5ldF90eXBlIjoxLCJ2aWRlb19pZCI6MCwiaXNfY2hpbGQiOnRydWUsInBhcmVudF9tZWRpYV90eXBlIjowLCJwYXJlbnRfaWQiOjAsImZlZWRfcG9zIjoyLCJwdWxsX3R5cGUiOjEsInBhZ2VfbnVtIjowLCJjbGllbnRfcmVwb3J0X2J1ZmYiOiJ7XCJzZXNzaW9uSWRcIjpcIjE0M18xNjE3NzEwNzYyNTY4IyQyXzE2MTc3MTA3NjEyNjgjXCJ9IiwiaXNfbGl2ZV9mZWVkIjowLCJpc19saXZlX2ZpbmRlcnVzZXIiOjAsImV4dF9mbGFnIjowLCJjb21tZW50X3NjZW5lIjoyMCwib2JqZWN0X2lkIjoxMzU2OTMyNDk0MzIxMDk3NzM0NCwiZmluZGVyX3VpbiI6MTMxMDQ4MDgwNjQ2MDA0ODYsInBvaW5hbWUiOiIiLCJjaXR5IjoiIiwiZ2VvaGFzaCI6MzM3NzY5OTcyMDUyNzg3Mn0=", "timestamps": 1617780210295, "urlValidDuration": 172800, "userName": "v2_060000231003b20faec8cae38f1dc5d5ce00e432b077b11d4f3ce9c011535e0fff9bba95dcc6@finder" }

这里要小心,过长的 long 在转 json 的时候可能会丢失精度,如果发现这种情况要特殊处理下,把 long 转成 string 。

数据处理视频问题

检查了下数据,发现通过 url+url_token 拼接的视频流虽然能下载,但是下载下来是加密后的,无法直接播放。

后来发现 url+thumb_url_token 是可以播放的,高兴了一段时间。但是4月26号左右微信好像做了什么操作,导致这个渠道不能播放了。经过简单分析后发现视频解码的流程是放在native方法中,一时半会难以破解,那就只能想办法下载缓存了。

(当然,这些加密算法在安全组的同学面前都不算问题,三下五除二就发现原来是某个比较小众的流式加密算法🤭)

文件追踪

利用 frida-trace 可以追踪app的系统调用,因此我们可以尝试看下 app 写文件的 open 方法。

$ frida-trace -U -i open com.tencent.mm

滑动下页面,我们发现了下面的日志:

看起来非常像是视频的缓存文件。打开一看,果然是。。。

那么,照着这个格式搜索下代码,稍微拼接下就能搞定这个缓存路径。

其他

调试过程中还发现一个查看当前调用堆栈的方法,可以辅助分析:

代码语言:javascript复制console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()))总结

头一次使用 frida 还是很有新鲜感的,用 Python 向 Android 中插入调用 Java api 的 Javascript 代码。。。

参考资料

基于Frida的全平台逆向分析

APP逆向神器之Frida

基于TLS1.3的微信安全通信协议mmtls介绍



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有