起因
学习一门技术,最好的方法是实际做一个项目。而做任何一个项目,最好的动力就是实际的需求。
我的一个需求就是把在钉钉(一个阿里的通讯软件,相当于企业版的微信)上对方撤回的消息显示出来。目的也就是想看看对方发了什么让自己觉得囧的消息想撤回,哈哈哈。
经过
工具
工欲善其事,必先利其器
xposed开发中80%的时间是用来对apk包反编译后代码的解读和思考(如果你在修改的开源代码,请跳过这一段。。。),因此想要开发xposed插件,必须学会apk反编译工具的使用。
列举一下我使用到的工具:
- apktool
- 用来将apk包解析后得到资源文件和smali文件(类似于汇编代码)
- 使用
java -jar apktool.jar d YOUR_APK_FILE.apk -o TARGET_FOLDER
命令 - 建议学习一下
smali
的语法
- jad-x,用来将dex文件(类似于class文件)转为可读的java文件
- 将apk文件后缀改为zip后解压,用
jadx-gui
打开每个dex文件,并save all
- 将保存下来的目录进行合并,可以使用*unix的
cp -r
命令处理 - 打开一个IDE(如果你喜欢用vim也行),开始找你要的代码吧
- 将apk文件后缀改为zip后解压,用
建议最开始主要使用jad-x
生成的java代码进行程序的理解,当涉及到一些资源的使用,或者jad-x
解析不了的代码时,使用apktool
解析出来内容进行挖掘。
另外,还可能涉及到抓包这个步骤,不过我目前还没有用到。
思考
Xposed开发其实本身并不会写很多代码,而是在于找到切入点,对源程序进行行为的改变。
比如要防止消息撤回,最先想到的就是让消息的状态永远是“非撤回”状态,然后考虑到数据库的变化,想到的是拦截数据库的修改消息状态(撤回)的动作。
寻找
寻找不仅仅意味着寻找代码,还可以是利用搜索引擎进行查找~
我找到了veryyoung
写的一个module,可以用但还是存在着一些问题。这也为我提供了不少的思路。
可以看到recallStatus
是一个关键字,我用它来检索了全部代码,找到了MessageImpl
这个类。可以看到veryyoung
是对MessageImpl
这个类的recallStatus
这个方法进行了hook,让它永远返回0
(1
表示已撤回)来达到阻止撤回的目的。
但依然存在两个问题:
- 应用重启后,被撤回的消息无法复原,即还是被撤回了
- 过去被成功撤回的消息,在对话框中显示为正常对话,而内容是”Msg has been recalled.”
尝试
首先我想到的是这个”Msg has been recalled.”是不是一个资源string,找一下看哪里显示了这个字符串,结果没找到。。。
后来我意识到了:
- 这个字符串不是显示的时候加载的,而是被写入了数据库
- 显示”Msg has benn recalled”的时候并没有和那些正常“已撤回”的消息使用同样的格式,而是和普通的消息使用一样的格式,也是因为这条数据就只是一条普通的消息
- 数据的来源可能是远端的请求,所以本地资源里找不到这个字符串
于是我的方向转为了寻找数据库的写入或更新,只要这条“新“的消息不覆盖原始数据,那消息就能够被正常显示了,即使本地应用重启也没问题。
同时结合关键词recallStatus
,我找到了MessageDB
这个类(代码混淆后类名变成了cuw
),在对几个可能更新消息内容的函数进行hook打印日志后,最终确定了某个函数。
这个函数在对方点击撤回时会在我这里被调用,且写入的消息内容正是”Msg has been recalled”。
Binggo!
总结
这个插件的源码地址是https://github.com/AaronGeist/DingDingHacker,欢迎提交issue。
我这篇文章也只是记录了一下开发的过程和思路,推荐大家读一下veryyoung
的这篇文章,能够对安卓的逆向工程基础有所了解
http://veryyoung.me/blog/2016/09/29/android-reverse-basic.html