转自CSDN《程序员杂志》 作者:火点,Orlando
任何一款独立的操作系统都离不开输入输出环节,并且输入输出的安全与否关于到使用这个操作系统的用户隐私安全,Android系统也不例外,而且用户对手机的使用频率远远大于PC,这使得它的输入输出安全越发重要。本文抛砖引玉,对Android输入输出系统安全深入浅出的分析。
简单的说,用户与手机的所有交互都是输入输出子系统承载的,用户通过各种输入设备向系统传达指令,如触摸屏,物理按键,各种sensor等等,然后结果输入子系统传递到某个具体应用完成用户想要的操作,然后通过输出子系统呈现给用户结果。由此可见,如果输入输入被攻破,用户的隐私数据将被轻松窃取,造成极大损失,如输入的银行卡号,密码,身份信息,隐私聊天记录,照片,视频等等,都有可能被窃取。那时,手机真的就变成手雷了。
那么,Android输入输出子系统到底安全吗?且看下面的分析。
Android输入子系统工作内容主要包括以下几点:
1. InputReader线程从按键,触摸屏等输入设备获取原始输入信息
开机后,Android中最重要的系统进程system_server中的InputManagerService在初始化中会创建两个线程用来处理输入事件,一个是InputReaderThread,一个是InputDispatcherThread。InputReaderThread在死循环中一直从EventHub中读取系统的输入事件,然后发送到InputDispatcher类中的一个队列里,用于InputDispatcher对其进行分发。
2. InputDispatcher线程处理InputDispatcher队列中的事件。
在InputReaderThread使用了epoll机制,当有新的输入事件线程被唤醒,把转换好的消息发送到相应的窗口去,通过InputChannel把事件发送给具体的app进程。
3. App进程收到事件后,最终通过一个view tree结构的根Décor View分发到最终会处理这个事件的Child View。
图1.输入子系统
上面涉及到2个进程通信,如果牵扯到输入法,就更复杂了,涉及到三方通信。如图2所示,输入法进程(以下简称IME,InputMethod),软键盘对于输入子系统来说就是touch事件,所有touch事件通过输入子系统到了IME进程,根据touch坐标转换成为真正的输入字符,然后IME利用InputConnection(实际上是对IInputContext Binder的封装)通过IPC将输入的字符串传给正在接受输入的app进程的某个TextView显示出来,传输的字符串都是明文啊!
图2.输入法通信模型
从上面的分析我们可以看到,输入的漫漫长路,任何一个环节都有可能被攻击,这里举几个例子。
0x01追根溯源
直接监听分析输入设备原始事件,在/dev/input/目录下的节点权限如下。
图3.Input设备节点
而通过adb登陆的shell因为调试需要,也加入了input这个group (如图4所示,可参考android系统源码文件adb.c),并且android内置了getevent事件工具,就目前经验,很少有厂商会从量产版本中去掉这个工具,所以可以非常轻松的通过adb shell拿到用户输入,整理如下,输入的坐标位置一目了然,如果再能结合其他信息,如使用哪个输入法,屏幕分辨率等,就可以计算出输入了哪些字符。也就是说一旦我们电脑中了病毒,而碰巧又是连接电脑在输入敏感信息,嘿嘿,那恶意程序就可以把所有的输入通通拿到,一览无余!
图4 adb shell调试权限如此之多
图5 通过getevent工具分析输入事件
0x02直击要害
前面的不过瘾,数据不直观,更高级的恶意程序可能已经获得了root权限,这样还不如直击要害,从前文分析中,在输入法通信模型中,直接注入截获InputConnection的commitText,就能轻松拿到输入字符,省事多了,如果你注入的是输入法IME进程,那些敏感app(如支付,金融,通讯类)的开发者可是要哭死了,因为它无法监控IME是否被入侵,只能心中无奈OS,“臣妾做不到啊!”。
0x03另类奇葩
很久之前听说一种名叫TapLogger的病毒,它可以通过动作传感器获取你的输入信息。也就是说即便是触摸屏幕的虚拟键盘,它也能搞清楚你到底在输入什么。据说4位数密码能够达到100%的正确率,6位能够达到80%的正确率。
如果说输入子系统因为流程复杂导致安全风险,那么输出子系统则因为简单,从而导致攻击难度降低。
Android输出子系统主要是经典的Composite模式,如下图
图6 输出子系统
每个App都会传递自己的surface到SurfaceFlinger,SurfaceFlinger做一次composite形成一个显示的buffer传给FrameBuffer,再不考虑Overlay buffer的特殊情况下,LCD直接扫描FrameBuffer显示在屏幕上。
问题就出在这个FrameBuffer上,在系统中最终会放到/dev/graphics/fb0节点,如果这个节点不小心被很二的工程师配置成others可以读写,恶意程序就可以轻松通过读取FrameBuffer内容达到截屏的效果,而且Android为了系统截屏方便,还自带screenshot工具对FrameBuffer做了封装,用起来非常方便。我们就在国内某著名厂商的旗舰机中发现了类似问题,如图7所示,网上流行的号称非root截屏的app其实就是利用这个漏洞实现的。
图7 有安全漏洞的fb0节点
即便是没有这个漏洞,others没有任何权限(如图8所示),但是通过adb登陆的shell因为调试需要,也加入了graphics group(这一点在上面图4中代码中也可以看出来),也就是说一旦我们电脑中了病毒,而碰巧又是连接电脑在输入敏感信息,嘿嘿,各种敏感输入,各种猥琐聊天轻松被截屏。又是因为调试,看来安全和调试果然是冤家,个人认为,安全更重要,显然Google在此时倾向于调试功能的丰富。
图8 无安全漏洞的fb0节点
近年来,芯片厂商,手机厂商,ROM开发者,甚至应用开发者对Android的深入定制都有可能引入新的安全漏洞。好的一面是Google已经越来越重视Android系统安全,随着版本不断升级,安全性也在不断提高,新发布的5.0使得手机root越来越困难,同时有实力的芯片厂商,手机厂商也在研发自己的安全解决方案,尤其是在移动支付领域,将安全带入新的高度。移动系统安全任重而道远。