很久前写的一篇文章,发出来以作纪念:)
Android中一个有趣的crash的日志分析
首先看看bugly平台中异常的统计信息,表面上是一个NullPointerException:
发生异常设备统计信息如下图,有意思的是全部都是root过的机器:
接下来看跟踪日志,在最下面可以看到这样的日志,抛出了NullpointerException:
引起异常的是com.lishu.net.LishuNet$2类,从类名看显然是某一个类的内部类。
第一个反应,当然是搜索一下应用的源代码,看看是不是有com.lishu.net.LishuNet这样的类,或者异常。如果有,那自然就是继续分析代码了。经过一番搜索,居然没有找到,看来有点意思。
其次自然想到,应用集成了很多第三方SDK,或许是某个SDK里抛出的异常?不急,解压出所有集成的.jar包,然后批量反编译,导入工具中全局搜一下,有没有这个字符串了。费一番周折发现,还是没有这个字符串。越来越有意思了,代码中没有相关的类,SDK中也没有,奇怪。
回来继续翻看日志上下文,只有如下信息可用,看来是个http访问超时异常:
有问题,这个异常和其他异常不太一样,日志里居然连com.chebada包名都没有显示出来的。也许是统计平台出错了,压根不是我们应用导致的crash?
只有抛异常前打出来的一行日志,看起来有些关系
访问这个网址看看,有时连不上,有时拒绝服务。源代码里也没有这样的网址。
这个时候线索好像真的断了,再搜索日志,看不出来和我们的应用有什么关联。
还是没有思路,再翻一下其他异常,发现异常列表中有些日志会打出来类似下面的内容,之后再访问上图中的网址(http://120.24.74.141:8080/lishu008AppManager/phone/LogicSimpleAction.action):
总结多个crash日志,发现每次都是先有这个js警告,再访问120.24.74.141域名。
js又是/data/data目录com.chebada包下的脚本,也许,是WebView的访问触发了相关异常,或许是url劫持?也不像。统计平台异常列表中有些并没有报这个js警告,问过服务器相关同事,js也没有访问http://120.24.74.141:8080/lishu008AppManager这样的网址。
不过所有crash日志都有访问http的超时异常。
疑点都集中在http://120.24.74.141:8080/lishu008AppManager这里。
继续万能的百度搜索,lishu008AppManager露出一点端倪。有一个名叫“008神器”的安卓应用引起了我的注意,该下载链接中有lishu008AppManager字样。打开主页看看该应用能干什么,结果吓一跳:
下载一个看看,运行需要root过的机器。 找了一台root过的机器,运行后按提示安装框架、安装模块。期间需要重启几次。
需要的框架、模块都安装好了,再次运行,提示软件到期。卸载重新下载一个破解版的“008神器”,运行后发现,能改的东西还真多,连手机串号也能改:
这个时候看看日志,发现了LishuNet的踪迹:
等等,“008神器”的包名不是com.soft.apk008Tool吗,怎么会报com.lishu.net.LishuNet错误呢?反编译apk安装包,原来,除了com.soft.apk008Tool,还有另一个包com.lishu.net这个包,其中有LishuNet这个类,LishuNet还有一个内部类com.lishu.net.LishuNet$2,继承自Thread:
显然在该线程中触发了NullPointerException异常。往下跟跟,具体打印出异常的地方:
这个就是在连接http://120.24.74.141:8080失败时,比如连接超时、服务器拒绝服务等异常情况下,打印出异常信息的地方了。原来只要连接出错,就会打印出错信息。
除了反编译代码中有com.lishu.net这个包,在 “008神器”安装包的assets文件夹下还发现了Apk008Tool.apk这个安装包,安装后会多一个“008神器工具箱”的应用。再反编译“008神器工具箱”,原来com.lishu.net是“008神器工具箱”的包名,而“008神器”中com.lishu.net包下的代码,都是从Apk008Tool.apk来的,最有可能的就是,“008神器”和“008神器工具箱”是同一个作者开发的。
那是什么触发了异常呢?各种尝试,后来发现运行“008神器”,就会访问网址http://120.24.74.141:8080/lishu008AppManager/phone/LogicSimpleAction.action,接着log中就能看到异常信息,过滤后显示如下图:
原来只要运行“008神器”就会报异常。继续跟踪com.lishu.net.LishuNet:
LishuNet对象调用postMessage()方法,在该方法中new一个LishuNet$2的对象,也就是新建了一个Thread线程,并开始运行。异常就是从这个线程里抛出来的。
那么,哪里调用了LishuNet的postMessage()方法呢?继续搜索,原来是在Apk008Activity的onResume()中:
其他地方也有调:
稍微跟踪一下代码,会发现,在“008神器”启动、启动其他应用、网络状态变化、调用工具箱修改了系统属性值时,验证“008神器”的签名时,等等,都会触发这个线程,调用postMessage()方法,向http://120.24.74.141服务器发送特定数据。以启动“008神器”应用发送的数据为例:
启动时发送的数据是手机的IMEI、系统版本号、系统版本名称。其他不一一列举。
原来异常是和我们的应用没有关系的,可以这样验证:卸载我们的应用,单独运行“008神器”时,log中依然会不停的报com.lishu.net.LishuNet$2的这个异常。
Bugly中报这个异常,极有可能是因为,bugly统计平台的SDK在安卓系统log中恰巧同时检测到了com.chebada,和com.lishu.net.LishuNet抛出的异常,就将两者结合,视为com.chebada的bug了。这也可以解释,为什么几千条LishuNet$2抛出的异常,没有统一的错误信息。后续有时间再反编译看看bugly统计SDK的代码,验证一下。
至于解决方法,实现起来就简单了,既然改不了框架层的东西,就在应用层修改。在应用启动时判断,如果存在“008神器”或“008神器工具箱”,就退出应用。OK,打完收工。
当然,如果使用008神器或者xposed框架接口,在系统服务层API屏蔽了008神器应用,那使用这种方式就不起作用了。
附:
“008神器”工作原理引起了我的好奇,各种改系统功能是怎么实现的呢?经过学习发现,是利用了xposed框架,而xposed框架是需要root权限才能正常运行的,这也解释了为什么报这个crash的设备全部都是root过的了,没有root权限,“008神器”就没法正常工作。
Xposed框架是开源的,不过作者(也是Supersu的作者)好久没有更新了,所以该框架只支持安卓4.0.3-4.4版本的系统,这个可以解释统计平台设备版本分布情况:安卓系统4.4版本以上信息不会报这个异常。
有兴趣的同学可以学习研究下这个框架,框架基本原理是修改了安卓系统的心脏zygote,等于在安卓的Java虚拟机上加了一个接口,这个接口为框架修改系统、提供系统级的服务提供了支持,当然,如果拿来搞破坏,其威力也是相当惊人的,可以在应用不知情的情况下,肆意获取输入的用户名、密码等敏感信息。下图是我写的框架Demo程序运行结果截图,拦截了应用登录页面输入的用户名、密码信息:
经本人实验,不修改第三方应用、不经用户同意,就可以在应用运行时动态拦截、修改应用的数据,并完全可以做到开启后台线程,将用户的数据发送至特定的服务器。
原文地址:https://www.cnblogs.com/areful/p/10399409.html