本帖最后由 XOR 于 2018-11-16 23:46 编辑
一、前言
之前刚刚分享了一篇破解支付宝自动生成付款二维码的文章,点我查看。这篇是对上一篇的补充,既然实现了支付宝的二维码生成,那么继续把微信的二维码生成搞定,把这个插件做的更完整一些。如果你只想随便看看破解思路,那直接看上面一篇就可以了,那篇思路比较清晰,容易看明白。
这次在破解过程中还是遇到了一些问题,我反编译的是微信6.6.7版本,可能遇到的两个最主要的问题就是:
1. 微信混淆的比支付宝要复杂的多,看反编译后的代码,大部分都是不相关的字符名称,看起来很费劲,而且用jadx反编译出来的代码,经常有错误的或者缺失的导航,直接go不过去,还需要去看相应的smali代码,找到正确的包名或者类的路径,是不是有更好的工具我不知道呢?
2. 我开始也是用DDMS的traceview去分析,但是感觉帮助不大,是不是我的分析思路不太对,因为像生成二维码这种需要网络异步操作的,我从traceview很难找准相应的发起和接收的方法,找一些点击事件倒还是很简单的。
有可能是我的分析方法不对路,如果论坛哪位大神看到了我下面的分析思路,有更简洁更好的方法希望能在留言中指点一下。
二、寻找突破口
其实经过了破解支付宝的过程,再去破解微信,还是有了不少的帮助的,比如你去对比一下微信和支付宝设置金额和备注,还有生成二维码的页面基本都是相似的,说明他们的流程基本也是相同的。所以还是先找到那两个最主要的操作页面,和上次的分析方法一样就不贴截图了,最后找到的是CollectMainUI(对应展示二维码页面)和CollectCreateQRCodeUI(对应设置金额和备注信息页面)。
一、CollectMainUI页面分析
先去看第一个页面CollectMainUI,其实有了上次的分析经验,我直接去找这个类有没有onActivityResult方法,也就是当你设置完金额和备注以后返回来时的回调,然后发现确实是有的:
从代码上看得出,标红框的代码应该就是设置以后返回的结果,每个字段的意义基本也都清晰,ftf_pay_url应该是二维码信息url,剩下的几个就是描述,金额,货币单位等等,然后这个case分支又调用了两个方法aoV和aCp,其中应该有一个是生成二维码的处理逻辑,先看aOv,它里面又会调用两个方法aCo和aCq:
如果你go到里面的方法去看看,就会知道他就是生成图像的工具类方法,有点类似之前支付宝分析中的按个辅助类,截图我就不贴了,我也没有仔细去看,反正已经找到地方了,但是还有一个问题,如果我们想使用这个方法的话,他的调用需要传递好几个参数,他们都是干什么的呢,会有哪些值呢?最简单的方法就是去hook一下这个方法,然后我们去操作生成二维码,调用的时候反射打印一下这个几个值,看看有没有规律可循,下面是写的一个hook的测试方法:
然后再看看打印结果是什么:
其中那个打了码的gf是从刚才说的yF方法中q.GF()这个调用获取的,为啥打码,因为他返回的是你的微信号。。。其他几个参数都没什么特别的,我们传0或者null就ok了。这里其实还有一个this.hYI我没有打印,因为他是一个内部类,用来下载图片用的,但是只有那个this.hYW为1时,才会用到,所以咱们使用的时候也直接传null就可以了。
总结一下CollectMainUI这个页面:
简单分析以后,知道了调用逻辑和支付宝相似,也找到了实际生成二维码图像的方法yF(String),实际内部调用的是com.tencent.mm.plugin.collect.b.b辅助类的a方法,有一堆参数,有用的没几个,那么这个页面就分析完毕了,剩下的我们就是要去寻找刚才那个二维码信息URI是如何在下一个页面生成的了。
二、CollectCreateQRCodeUI页面分析
这个页面,最主要还是要关注那个【确定】按钮点击后的逻辑,因为只有确定以后才真正的去请求二维码信息:
它实际处理的是一个内部类:CollectCreateQRCodeUI$3,直接看看onClick的处理吧:
从上到下,就是把金额double值做一下转换,然后一堆分支,很明显前两个都是toast警告你输入非法值,后两个调用哪个呢?方法都是一样的只不过参数不同,这里有两种办法来确定调用的哪个分支,我们看到其中那些红色的都是jadx反编译以后信息对不上的,你直接找不到源码对应的路径,所以可以去看smali代码,确定那些变量的意义,缺失的包名等等,或者咱们再来hook调用的那个方法,看看到底是哪一个,我就不贴代码了,这里直接说,就是最后一个分支。这个方法,第一个参数是new 了一个com.tencent.mm.plugin.collect.b.s类型的变量,这个需要go进去看一下:
我们先看构造函数,也就是代码块(1),没错,就是把你设置的金额和备注放到Map中,然后调用了一个F方法,这个方法明显是一个基类中的方法,你往上去找这个类的基类,就会找到,位置在com.tencent.mm.wallet_core_c.i,代码比较长:
里面还会调用一些方法,我也没去看,反正从这个函数大概的代码和注释上看,应该是把网络请求做了一些封装,然后我们再返回去看上一张图中的代码块(2),我在看到这个函数的时候,我就猜测它很可能是网络请求后回调结果的地方,到底是不是呢,hook看一下就知道了:
可以从结果上看到,返回的JSONObject里面的pay_url就是我们需要的二维码信息URI,那么这个类的作用也比较明显了,我觉得就是一个对二维码网络请求作封装的包装类,包装了请求的参数以及提供了请求结果的回调解析。 那现在最最关键的问题就是,这个网络请求是在什么地方发出去的呢?毕竟我们如果知道发送请求的方法,就可以按照方法调用去构造参数,然后自己在插件中去请求了,然后我就在这里卡住了 ,最开始呢,我用traceview去找有没有可疑的地方,但是这种异步请求,我是没找到地方,也可能是方法不对路,没办法,只能再看看刚才说的onClick方法:
这种混淆很严重的代码看起来很枯燥,但是找不到地方也只能去看看这个方法的实现了,它内部简单处理了一下以后,最终调用的地方是:com.tencent.mm.wallet_core.d.i的a(l lVar, boolean z, int i)方法,
几个可疑的地方,第一个红框的q(lVal),进去看了一下,只是设置了几个变量而已,而且我hook方法验证了一下,应该都是空值,看来和他没关系,排除,第二个红框的变量this.eXG是个Dialog,当你设置好金额【确定】的时候就会走到这里弹出一个loading框等待网络请求返回,最后面的红框代码块(1),很可惜jadx反编译的有问题,看一下对应的smali代码:
原来这个dpP是com.tencent.mm.ab.o,那最后看一下它的a方法吧:
经过一些assert断言以后,实际调用了b方法,这个方法很长,我没仔细看,但是简单看过这个o类以后,基本可以知道他是把请求放到一个消息处理队列里面,然后一个个开始执行,所以实际调用发送请求的方法就是这里,你可以去按照a方法来构造调用,你也可以按照b方法来构造调用,都是一样的。
所以再来总结一下,设置好金额和备注后,将参数封装(使用的是com.tencent.mm.plugin.collect.b.s)成一个请求参数,然后将请求参数放到队列里等待执行(使用的是com.tencent.mm.ab.o),所以我们可以按照这个逻辑走早好参数,调用方法加入任务队列,然后hook com.tencent.mm.plugin.collect.b.s的回调方法。
三、总结
我破解的思路就是上面这样,不像支付宝那么思路清晰,微信混淆的很严重,而且目前算个半成品,只支持微信6.6.7版本,每个版本差异还是有的,所以别的版本还有问题,但是好在有了分析支付宝的经验,还是能够找到正确的地方来解决问题,最后XPosed hook相关的代码我就不贴出来了,都提交到github上了,地址不变
https://github.com/wayu002/AlipayQRHook,项目名称起得比较尴尬。。。本来没想破解微信的
|