Android逆向之免Root实现微信消息同步原理解析
现在很多应用有一些需求需要获取监听微信消息,然后做一些事情,有的会把当前微信聊天信息直接同步到服务端进行分析用户行为,这么做可能为了更好的用户体验,但是这样是很不安全的对于用户来说,因为微信官方都说不会保存用户聊天信息的,不过本文单纯从技术讨论一下有没有免Root进行操作,当然Root之后就不多说了方法太多了。## 通过辅助功能和截图功能
因为是免root所以用到的东西全都是系统api做出来的效果下面说一下具体实现原理,本功能主要用到了AccessibilityService+MediaProjectionManager+文字识别。
第一、辅助功能AccessibilityService无障碍类最初的设计理念是帮助残疾人的但是在国内被做成黑科技 ,比如自动抢红包,自动安装 app,等一些实现场景,这个类可以对每个APP进行监听获取一些view的控件信息!
第二、MediaProjectionManager这个是5.0以上谷歌开放的API主要功能就是截图当然需要用户开启权限!
在这之前读者们可以百度看看这几个相关的API,网上的帖子说的都很不错,不然的话看下面可能会有一些吃力,如果想做到消息同步就首选要确认的是用户是否发送了消息?笔者之前寻思用发送按钮的监听方式 进行get 消息处理,但是发现如果这样的话不可以对对方发送的消息进行获取。
也是想了很久,后来发现一件事,我可以对微信聊天页面的ListView 的事件进行监听操作, 在AccessibilityService里面有一个方法可以处理每个 View 各种事件比如单机长按滑动状态变更等,都有很明确的记录,我只需要做到当聊天页面的ListView 的控件进行滑动监听即可获取有人发送了消息因为微信聊天页面整体是一个ListView (可以通过 DDMS查看对应的控件节点信息 )可以通过DDMS 的方式拿到对应控件信息如下图所示:
拿到指定的信息以后通过AccessibilityService 提供的 findAccessibilityNodeInfosByViewId(ID)或者ByName方式拿到对应的控件,返回的是一个List<AccessibilityNodeInfo> 因为一个节点里面可能会有多个节点,简单介绍一下 AccessibilityNodeInfo也是有助于下面的学习,这个是相当于获取每个节点的详细信息,里面有一些常用方法,getText() 获取View的文字内容,getChildCount(),获取控件子View的个数等,在WX里面ListView里面是一些自定义的View,如果直接对聊天的View 进行获取进行getText()返回的是NULL 微信在这个方面做了处理 ,在抓狂的时候,笔者发现在 一个方法:info.getBoundsInScreen(rect);这个方法的大概意思是获取view在屏幕中的位置,需要传入的是一个Rect有过一些开发经验的可以知道一个 Rect可以定位到一个 View的具体位置如下图所示:
而info.getBoundsInScreen(rect);传入的 view 经过处理以后返回的正是一个view的具体位置 ,笔者是先用了MediaProjectionManager(网上有很多写好的代码笔者就不在这里列举了)对屏幕进行截屏然后获取 Rect以后在在对截屏返回的 Bitmap 在根据 Rect在对 Bitmap的进行截取,效果图如下:
第一次截图
第二次截图
最终结果就如上图,下来就可以利用文字识别 Bitmap文字内容即可,在Github上面有很多好的文字识别集成进去即可,然后用文字识别拿到的信息通过推送发送到另一端即可,大概实现原理。如上所述以上实现以后还有很多问题
### 问题1:如何拿到和谁聊天?
这个只需要对联系人的ID进行获取,然后通过上述方法找到位置,然后截图文字识别拿到,就可以拿到,这里需要注意每次切换到聊天页面都不一定是同一个联系人所以,每一次进入聊天页面都需要进行处理。
### 问题2:怎么判断是否是聊天页面?
大家伙可以用 DDMS 的方式去找找相关的控件信息,在聊天页面的话有一个返回的按钮,左上角的小箭头而主页面没有可以根据这个view 是否存在判断是否在聊天页面还是主页面。
### 问题3:怎么判断是谁发送的消息是自己还是对方?
可以获取头像的 View然后 getBoundsInScreen返回的Rect的右进行处理如果在左半屏幕就是对方发的消息右半屏幕就是自己发送的消息。
### 问题4:微信的每个版本的ID都不一样怎么对全部的微信版本进行操作?
这个笔者也没啥好的办法,最后的办法是在后台做一张映射表 对应着每个版本控件的id,每次开启辅助功能的时候获取一下微信版本指定的ID。
### 问题5:如果在聊天页面的时候别人也发送了消息应该怎么办?
因为是免root做的所以只能获取当前屏幕所以不支持如果有兴趣的可以研究研究对屏幕的状态进行监听获取发送消息的通知栏也是可以的。
### 问题6:如果之前和这个联系人有聊天内容,那获取ListView的 getChildCount不准确怎么办?
因为需要对最后一条消息进行获取,所以需要获取ListView的子view的最后一条消息内容,笔者发现如果你和别人有100条记录,ListView只能显示20条最多(getChildCount返回的是20)如果有新消息就是21,我们可以每次进入聊天页面获取ListView 的子孩子个数,这样就可以拿到最后一条。
下面来分析这种方式有哪些问题和限制以及安全问题,我们从上面的原理知道,大致通过辅助功能和截屏功能实现的,那么这两个都是需要用户授权的,而且这两个权限在之前也提到安全性是要值得关注的:
**第一、辅助功能**,我们可以监听到当前应用打开页面,如果有恶意应用在后台监听到是社交或者支付应用的登录页面,就伪造一个钓鱼页面,然后让你输入用户名和密码是他的钓鱼页面,这样就被窃取到了用户信息,非常危险!
**第二、截屏功能**,这个之前介绍一个漏洞问题说到了,本身截图功能就非常危险,比如金融类应用要是被偷偷的截图了,那么用户的财产敏感信息就被获取到了非常危险!而对于这种情况,我们做应用开发的时候如果有一些页面非常需要保护,可以设置一个安全属性:**WindowManager.LayoutParams.FLAG_SECURE**
比如上面的微信可以把聊天页面加上这个属性,这样截图就失败了:
所以用户在使用应用的时候一定要注意正规应用,然后就是有哪些权限是必须要开启的,不要随便开启一些权限,否则后果不堪设想。
下面继续来看,上面是通过截图然后图片转换成文字获取消息的,那么假如不在聊天页面怎么办呢?比如锁屏或者在使用其他应用的时候,这个就需要借助通知栏监听服务NotificationListenerService了,这个也是需要用户自己开启权限的,这个服务具体用法就不多介绍了,感兴趣的同学自己网上搜索看看,可以监听到通知栏的消息内容,这样微信在后台就可以获取到信息了,但是这种方式有个问题就是假如用户把微信的通知栏功能关闭了就没办法了,不过一般很少人会关闭微信的通知栏消息功能。
页:
[1]