问题背景
最近在研究小程序相关的安全问题,需要批量搜索、获取各端小程序。微信小程序之前可以直接使用subsearch的API来获取小程序的信息(虽然cookie有效期有点短)。但是现在新版的微信改用了其他方式,旧版微信也搜索不到小程序了,这个api似乎确凿是关闭了,因此需要另找一个比手动搜索效率更高的方式。
尝试思路
第一反应当然是看看换成什么别的API了,但是出乎意料的是,旧版微信上非常容易抓的包在新版中居然一个都见不到了,尝试了no_sslpinning和vpn转发的方式也没什么效果。约莫又是用了什么神奇的协议。
但是好在hooking可以一力破万法,不管什么协议总有个获取明文的地方,接下来就一头扎进代码开始逆向。
逆向寻找调用点
进入微信小程序的搜索界面,看看对应的activity:com.tencent.mm.plugin.webview.ui.tools.fts.MMFTSSearchTabWebViewUI
很好,看看里面代码长什么样:
评价为是空空如也。
换个思路,试试直接hook socket相关的类:
调用栈里可以说是一点线索没给留下。但是不要气馁,在刚刚的初步逆向中可以发现,微信里大量调用了一个MicroMsg开头的log(com.tencent.mm.sdk.platformtools.Log),hook这个类想必能打印出很多信息(实际上有点太多了)。经过漫长的筛选,发现这样一条记录:
一眼看出这就是客户端获取的查询结果,那么看看调用栈中的com.tencent.mm.plugin.websearch.n$c,这个类应该是n的一个内部类,在处理返回包的时候run函数被安卓生命周期调用,因此调用栈里信息不足。
虽然我们直接hook它的构造函数,可以得到更早的调用信息,但是这整个流程都是处理服务器response的回调,继续追踪下去意义不大(血泪教训)。
既然已经得到了获取返回值的函数,只需要寻找触发这一流程的起点,就可以实现自动化搜索小程序。
思路清晰之后,不难想到,我们需要找到这个搜索按钮的onlick函数。这个onClick必定在当前activity里面注册了onClickListener,既然我们看到的activity里面没东西,那么肯定是在父类里注册的。它的父类是com.tencent.mm.plugin.webview.ui.tools.fts.FTSSearchTabWebViewUI:
细细一看也没有什么相关逻辑,只有一个取消的按钮。
那么再看看父类的父类com.tencent.mm.plugin.webview.ui.tools.fts.FTSBaseWebViewUI:
混淆比较严重,但是没关系,我们用objection直接hook所有函数,看看点击按钮的时候是哪个被触发了。结果来说,直接相关的只有p8,其中一眼就能看到这么一段代码:
q3是一个WebSearchView类型的成员,那么毫无疑问,它的FtsEditText就是我们的搜索框。getFtsEditText()返回的类是com.tencent.mm.ui.search.FTSEditTextView,看包名感觉离我们的目标已经很接近了。
这个类注册了好几个onClickListener,逐一排查之后,终于找到了我们追寻已久的按钮
经过测试,直接调用这个onClick函数的效果与我们手动点击是一样的,因此只需要在这里传入我们想搜索的关键字,再在之前找到的log里去取返回结果,我们就能完成小程序的自动化搜索。
编写Frida脚本
1.触发onClick,这里需要传一个View当参数,我们用Java.choose找到当前的activity,用findViewById就能拿到这个button。(button的id在之前的逆向里已经通过getId()获取)
2.传入我们想要的关键字。FTSEditTextView类通过getInEditTextQuery()和getTotalQuery()获取text的文本,hook这两个函数把返回值改为我们想要的值。
3.从Log里读取返回结果。
相关脚本已经整理在本人的github:https://github.com/realvegechick/FridaRepository/tree/main/WeChatMiniAppSearcher
很可惜返回值里并没有appid,因此要批量下载的话还是需要结合uiautomator进行模拟点击。