Android"挂逼"修炼之行---微信摇骰
一、前言
在之前的一篇文章中我们已经详细介绍了Android中Hook工作的一款神器Xposed工具:Xposed框架原理解析和使用案例分析 在那一篇文章中我们介绍了如何安装Xposed框架,以及如何使用Xposed库编写第一个模块来做到修改系统方法功能的效果,同时也说到了一个非常重要的知识点就是:在Hook过程中最重要的一点就是如何找到Hook点,而对于这一点很多同学都会感觉到非常的困难,因为对于修改系统方法还好,因为可以简单的去查看具体的Android源码即可,但是如果说要去编写一些应用和游戏的外挂的话,那么第一步就得先去破解对应的App找到指定Hook点,这一步是非常困难的。所以只能多尝试多破解慢慢长点经验即可。
二、猜想假设
本文就借助之前的Xposed框架来介绍如何编写微信的一个外挂功能,这个功能就是微信摇色子和剪刀石头布的作弊器,我们用过微信这个功能都知道,是一个比较常用的功能,因为在一个群聊中会很无聊就来这种简单的比赛,谁输了发红吧啥的。那么这个功能肯定伴有随机性,而且我们应该相信这个随机方法肯定是在微信代码中的某个地方,所以如果我们找到这个方法了,那么就可以进行Hook他,然后拦截返回最大的数值即可,也就是我们想要得数值。
三、准备工作
上面大致分析了这个功能的原理使用,下面咋们就不多说了,直接进行操作,本文用了一个微信的老版本做测试的:微信6.3.9.apk ;那么第一步咋们得逆向微信,需要做两个工作:
第一先使用apktools反编译apk,这个不用多说了,微信没有对应用进行加固,所以反编译过程很正常。
第二需要借助可视化反编译工具Jadx来打开微信apk,因为微信应用很大,所以得慢慢等待一会才可以打开。
四、逆向分析
下面在来冷静分析一下如何我们该怎么入手?上面反编译成功了之后,还得寻求入口,这个入口也很简单的,因为我们想得到这个随机函数,那么在我们能看到的效果是色子,我们可以选择一个微信聊天对话框,然后点击一个色子功能:
看到了,我们点击色子之后肯定会调用这个随机函数获取随机值,那么这里就是我们的入口,所以第一步肯定先找到这个点击事件,如果要找到点击事件,那么就得先找到这个控件的定义,那么问题来了,如果能够快速的找到这个控件的定义呢?这个技术在我之前的一篇文章中已经介绍了,就是 微信的自动抢红包功能 当时因为要找到那个红包的点击事件,所以就用同样的方法来得到那个红包的控件定义的地方,而这个方法就是借助AndroidSDK提供的一个工具:uiautomatorviewer.bat 这个工具位于SDK目录的tools目录下,我们可以点击运行,然后就可以看到这个界面了:
我们把设备停在聊天对话框中,然后使用这个工具,点击左上角那个按钮,可以进行当前桌面的界面布局分析,分析结果我们可以看到,这个色子是一个自定义控件:com.tencent.mm.ui.MMImageView,然后他的id是ae7,而这个值非常关键,后面就是用这个值来进行一步一步的跟踪,这里我们再多看一眼,就是这个表情区域的详细布局:
猜也猜到了,表情区域外面应该是一个ViewPager控件可以进行滑动切换,然后是每一页的控件用的是GridView进行卡片分割,那么这里就会给我们一个提醒了:后面的点击事件要么是在GridView的适配器类的getView方法中对view进行setOnClickListener添加的,要么是对GridView添加onItemClick事件的。
好了下面继续跟踪,因为有了那个色子控件的id了,下面咋们可以直接用这个id去全局搜索这个值了,不过这里有个问题就是微信其实本身做了资源的混淆,而这个混淆一方面是加大安全工作,一方面是减小包的大小功能,我们可以使用解压工具简单的查看他的apk文件中的res目录,会发现全是字母文件夹。而且从上面的id命名也可以看到,我相信微信工程师不可能会傻逼的把一个id命名成ae7了吧?到这里我们又要借助一个知识点了,而这个知识点在我之前的一篇文章中介绍了:Android中的应用攻防之战 在这篇文章中介绍了,我们在反编译apk之后,其实apk所有的资源id值都会保存在一个public.xml文件中,而这个文件是放在values目录下的,这个文件主要存放的就是资源的id值和name,type之间的对应关系,而反编译之后的代码中一般不会用R.id.xxx这种样式来访问控件,而是用转化之后的id值,这个值是十进制的,所以我们得先用上面那个ae7的id值去public.xml文件中找到对应的十六进制值:
注意:
这里在查找ae7的时候,会发现多个匹配项,而我们需要用额外的信息来作区分,那就是type字段了,type字段有很多种值,比如layout,drawable,string,attr,id等,我们这里因为是定义控件的所以type=id。
找到这个项之后,就把后面id的十六进制值转化成对应的十进制值吧:0x7f07060e=2131166734
有了这个值,就好办了,咋们直接在Jadx中打开的微信apk中全局搜索这个值:
哎,可惜的是没有找到,所以到这里就开始蛋疼了,也是这次逆向的最大阻碍了,想了好长时间,最后才突然想起来以前 逆向微信的本地通讯录信息 的时候发现微信采用了分包技术,也就是微信包太大,因为Android系统中有方法数的限制所以需要对apk进行拆包操作,具体可以查看这篇文章:Android中应用拆包技术详解 那么我们会发现反编译之后也没有看到多个dex文件,所以这时候还要猜想他应该是存在本地目录的,在应用启动的时候主dex功能再去加载这个次dex文件,通过查看反编译之后的目录,结果在assets目录下找到了他:
而这个是两个从dex文件,这里他做了dex文件转成jar文件的操作了,所以我们先用解压工具解压这个jar文件,得到对应的dex文件即可。然后咋们在开启一个Jadx窗口打开这个从dex文件,然后在全局搜索上面的那个值:
看到了,终于找到了这个控件的定义的地方了,点击第一个进去查看:
我们在往下面看这个类的信息,会发现到有一个getView方法:
看到这个就可以判定了,这个类其实是一个BaseAdapter类型了,而在getView中没有看到控件的点击事件,所以猜想应该是外部给GridView添加的onItemClick事件了,咋们继续选中这个类名,然后右击进行跟踪这个类在哪些地方被调用了,这个功能的确很实用的:
点击查找之后,会有很多地方调用:
这里从第一项的那个参数命令可以猜想到了应该就是GridView类型,而到这里我们貌似看到了胜利的曙光了:
然后查看这个smileyGrid变量的定义:
这里是一个SmileyGrid类型的,咋们可以全局搜索这个类,看看他的定义:
果然不出所料,这里是一个GridView类型,然后也看到了我们非常期待的onItemClick方法了,下面就开始分析这个onItemClick方法的逻辑了:
这里我没有找到一个好的办法,也不想去深入跟踪了,因为这里的判断分之不是很多,所以就顺序的尝试了每个方法,结果找到了最后一个a方法,然后点进去查看逻辑:
这里我们就需要多想点了,从我们点击色子之后的效果看,没有对话框和toast提示,那么这里就只有两个分支是最有可能执行的了,通过顺序尝试之后,发现是第一处分支的逻辑了,也就是h.a.aMZ.b()这个方法执行了,通过import导入的类,得到这个类的路径定义:
但是在这个dex中没有找到这个类,所以猜想应该是在主dex中,果然找到了这个类定义,然后进入这个类进行想详细查看:
继续进入看看b方法的定义:
擦,这里的b方法尽然返回的是null,那么到这里就要思考了,如果返回null的话,之前的点击事件肯定是无效的,而这个又不符合实际情况,所以猜想还有哪个地方对这个iop进行赋值操作了。我们看看这个iop定义:
从定义上可以看到,极大可能在其他地方进行了赋值操作,所以咋们全局搜索这个变量值iop:
发现搜索结果还是我们刚刚看到的返回null的代码,所以咋们又得继续去另外一个dex中进行搜索了:
这里搜到了一个赋值操作,立马点击进入查看:
然后查看PD方法的定义:
继续查看这个g类定义:
看到他的b方法,这里有一个bb.pu这个方法比较可疑,因为最终返回的值都是和他相关的,而这个方法在这个dex中又没有找到,所以咋们看一下他的import找到全局定义路径,然后去另外一个dex中查看定义:
到这里,就会非常激动了,因为我们看到了胜利了,这个非常明显的随机方法终于找到了,而通过这个随机公式可以看到,这个方法的功能是返回一个0-i之间的随机值,而对于色子应该是0-6之间的值,猜拳是0-3之间的值。所以这个方法百分百是用于随机功能的。
五、掌握逆向技能
到这里我们就成功的找到了我们想要Hook的地方了,从上面的逆向过程会发现微信的工程非常庞大,而对于我们逆向来说工作是非常艰难的,但是还好我们有一些强大的工具可以快速的定位问题,下面就来总结本文逆向收获的知识:
第一、对于逆向中想得到控件点击事件入口,可以通过以下步骤来进行
1、使用界面分析工具得到指定控件的id名称
2、通过id名称去反编译之后的values/public.xml中查找到指定的值,转化成十进制
3、通过Jadx自带的全局所有功能,查找这个十进制值即可
对于这个步骤将适用于想得到一个应用中某个控件的点击事件逻辑入口是非常有效的,而且也是通用的方法。
第二、对于微信来说,因为工程的庞大,所以肯定会存在拆包现象,所以他不止一个dex文件。肯定是包含多个dex文件的,所以后面还需继续写微信的外挂,到时候分析都是要注意这一点。
第三、对于Jadx的强大工具在本文中起到了非常重要的功能:跟踪方法的调用,全局查找功能。
额外说明:
在本文中我们会发现有一个难受的地方就是多个dex文件之间查找相应的方法的地方,所以其实我们可以这么干,我们如果得到了应用所有的dex文件之后,可以将其先转化成对应的java类,然后进行类合并,这里我们可以使用Beyond Compare比较工具将多个不同文件夹合并到一起:
合并之后咋们在用工具将其转化成一个dex文件,也就完成了多个dex文件合并工作了。在这个工程中,我们可以非常巧妙的借助Jadx的另外一个强大功能,就是可以把反编译之后的内容保存到本地:
他有个好处就是,把apk中的dex保存成java文件,资源全部解码保存指定xml文件,而最终的保存样式是一个gradle工程,而这个工程咋们就可以直接导入到一个开发工具中了非常方便了。特别是资源文件,我们在之前会发现apktools工具并没有反编译xml文件出来。而在这里就可以了。
六、开始拦截操作
下面咋们就来进行Hook操作了,上面已经得到了这个随机函数的名称了:
com.tencent.mm.sdk.platformtools.bb.pu(int i)
Hook工作就非常简单了,咋们拦截这个方法之后根据传入的值做一次判断是摇骰子还是猜拳操作:
首先咋们得做一次过滤操作,就是只会Hook微信应用,然后到拦截操作中,通过传递的参数做判断是摇色子还是猜拳,如果是摇色子就返回一点,猜拳就返回剪刀。
编写成功之后,就进行编译成模块,然后重启设备生效,点开微信打开一个聊天框,开始摇色子:
通过打印值可以看到,我们的猜想是正确的,看一下实际效果:
哈哈哈,所有的操作都在掌控之中,到这里我们也成功的编写了一个微信外挂功能,而这个外挂可能有的同学感觉用途不是那么大,而现在主流的外挂是可以防止撤销功能,分享视频到朋友圈,不过这些功能都会慢慢讲解的,不要着急,而对于本文以及后续的外挂内容文章,我想表达的是,结果并不重要,重要的是整个逆向过程,在每次一逆向之后我们学到了什么,是否涨了逆向经验,这才是我们需要得到的。
补充说明:
第一点:有的同学会发现咋们上面得到的那个方法貌似是混淆之后的,也就说如果哪天微信改了混淆机制,那么这个Hook就失效了,本文中用到的是微信6.3.9的版本,对于其他版本我想这个方法类名应该是变了,也就说如果微信每次出一个版本咋们都得去逆向一次得到方法名,但是这个都不是难事,以为本文已经将整个逆向过程讲解了,所以以后只要按照这个步骤来,查找方法也是分分钟的事!
第二点:本文的用意是分享逆向技巧知识点,所以也请各位同学能够知道结果不重要,重要的是整个逆向的过程,也就是如何寻找到Hook点
严重声明:本文介绍的知识点完全是从一个技术分享角度出发,绝非用于任何商业活动和用途,如果涉及到任何法律问题将由操作者本人负责。本文作者将不负责任何法律责任!也请各位同学秉着技术角度出发的原则,切勿用于商业中!
七、总结
本文主要介绍了一个微信的简单外挂功能,就是摇色子和猜拳作弊器功能,而在整个过程中,我们可以看到找到Hook点才是最关键的,而最难的也是找到这个点。一般都是需要进行逆向分析微信应用找到这个点。在这个过程中我们又学习到了一些新的逆向应用技巧知识点,后续将会继续带大家一起分享其他的外挂功能知识点,敬请期待,同时也要多多支持扩散分享啦,也要多多点赞呢?写这篇文章实属不易呀,因为逆向的我头都炸了!
更多内容:点击这里
关注微信公众号,最新技术干货实时推送