最近拿到一台测试手机(魅族x4),安装的是微信6.5.16版本,登录微信,发现竟然提示版本太低无法登录,简直不友好
最近在研究xposed,正好拿来练练手,这个版本号的校验肯定是本地的与服务器的进行了对比,然后得出本地版本号的低,所以我们只要找到连接服务器的网络请求,把传给服务器的版本号改了就好,首先通过dumpsys命令来确定 当前页面所在的Activity ,也可以使用 android sutdio自带的ADM,只是我的ADM 打不开,这里只能用dumpsys了
发现 Activity 路径为 com.tencent.mm/.ui.account.mobile.MobileInputUI
然后我们使用工具,apktoolkit,或者 ApkIDE 来反编译apk包来获取到资源文件,反编译后的java文件都是以smali格式的,看着实在让人头疼,就直接解压apk包来使用dex2来反编译成java文件吧
反编译后的文件 可以使用jud打开 也可以使用 luyten打开,他们的区别是jd可以打开多个jar文件,lyuten每一次只能打开一个,如果想打开多个就要开多个luyten客户端,但是luyten对java的支持比较好,反编译出来的代码看着更舒服。
打开 MobileInputUI 后发现一共有三个button,但是只有 v v V这个button设置了监听
那么我们就从这个button入手,当然如果三个button都不是,还可以找找textview,监听里面 GMTrace 应该是一个工具类,感觉是记录函数执行和结束的节点的,暂时可以想不看,那么就剩下 MobileInputUI.e(MobileInputUI.this); 这一行代码段了,我们点进去查看一下
这是一个static方法, 里面也只有 mobileInputUI.bWk(); 这一行有用代码,继续
这里有两个调用,先看第一个 this.aKl(); 发现lyuten并点不进去方法体,这个时候jd的优势就体现出来了,jd可以在打开的所有jar文件中查找方法调用
继续
发现这里个应该是进行了输入法键盘的设置操作,并没有什么有关系的代码,那么只剩下一个函数了 this.vzQ.AO(a.vzU);
点击进去发现是一个接口b,那么就要找到vzQ的初始化地方,全局搜索一下,如果要初始化,肯定要先看onCreate 或者onResume方法,直接先到onCreate方法中,
发现初始化的地方还是蛮多的,那么就要知道到底是初始化的哪个,b,c,d,e都继承了b接口,主要是根据 this.vzP 进行区别,那么好办,直接hook oncreate方法 打印一下vzp的值就行了,
。。。。hook过程省略
最后得出vzp的值为 - 1 那么就应该是e这个类,我们找到e这个类
查看AO方法,发现这个方法里面用到了很多变量做判断,那么一定有这个类变量初始化方法,那我们再回去看onCreate方法,看到下面有调用vzQ 的a方法
进入到vzQ的a方法,发现AO方法很多地方都用到这个 vzw就是刚才传过来的 MobileInputUI类
然后再回到 AO类
发现这个函数根据case对应的值可以走三个分支,下面两个都是一行代码,可以先点击进去看一下,
根据名字,一个可能是同意协议的弹框,一个可能是注册有关的,都不是我们想要的,研究上面的就可以了
这里我们需要vuD,类中搜索下这个vuD赋值的地方
发现是从这个a函数中传过来的,好办,hook一下这个a方法 ,或者hook一下下面的w.i log打印也可以
这个errCode 就是我们想要的vuD -106那么可以直接把下面这两段代码pass
this.vzw.vzO = an.Rj(this.vzw.countryCode); 根据名字 这段应该是获取登录环境国家代码信息
接着看下面代码 应该是判断字符串是否为空的
hook一下vzw.hfm字段可以得出最后走的是这段代码,那么可以直接看这段了
然后hook hMA好mbz的值,发现这两个正好一个是登录的手机号一个是密码
那么直接到eY这个函数
用户名密码我们都已经知道不为空,所以可以直接看最后的else,里面有个一个dialog框,并且有一个字符串,最喜欢找有字符串的了,如果字符串的值可我们界面上面的一致对我们分析非常有帮助,点进去看
这个在R文件中值为 2131234003 , 转换为十六进制为
还记得我们刚开始反编译出来的资源文件吧,拿着这个值 到 values 文件夹下面的public.xml 搜索一下,
得出来的 bny在到 string.xml中搜一下,看到 是 正在登录... 这个和我们刚才操作看到的一样了,我们点击登录,弹出来这个框,然后提示我们微信版本过低
这个函数中定义了弹框之后就没有其他代码了,所以发起网络的请求最有可疑的就是下面的两行代码中
第一行 final u u = new u(s, text, null, 1); 我们知道s,text 一个是用户名,一个是密码,然后构造出来一个对象,然后把对象传给了下面这行代码 ap.wT().a(u, 0); 所以可以猜想是不是上面构造了一个网络请求对象,进去u方法中
发现了上面这行代码,updateVersion 和clientVersion,clientVersion很明显是客户端版本的意思 那么直接进去
com.tencent.mm.protocal.d.toX 中看
这个tox的值很可疑,很有可能就是我们要找的版本号,上面写了一个固定的值0x26051034,下面又在配置文件中获取了一下,
那么简单 我们直接到配置文件中获取一下这个值,发现是和上面固定的值一样,那么这个就简单了如果是版本号,那么哪个版本的apk这个值肯定不一样,我们去找一个新版本的对比一下就知道了,找到了一个7.0.3的版本,得到的值为 0x27000334 比这个大很多。
那我们就可以hook看哪里调用了这个值,直接修改这个tox的值,换成7.0.3这个
hook代码省略。。。
修改完后再继续登录,点击登录,发现提示安全验证,已经不是刚才的提示版本号太低了
验证通过后,再点击登录
提示查看通讯录,ok,登录成功。
总结一下,这其中主要是hook了一下版本号,其实,最难的是寻找hook点,hook操作很简单,这其中也走了不少弯路,还是要细心观察代码,之前打印w.i日志的时候就忘记了有可变参数的情况,耽误了很长时间。