AccessibilityService防御

文章讲述了如何检测和防御滥用AccessibilityService的情况,包括通过AccessibilityManager获取已安装和启用的服务列表,干扰辅助服务的执行逻辑,屏蔽文案检查以及阻止点击事件。此外,还提出了通过随机发送事件来混淆外挂执行和禁止相关软件安装的策略。
摘要由CSDN通过智能技术生成

前面讲解了AccessibilityService知多少,详细描述了使用方法已经内部的原理,这节主要是防御手段。在网上也找到了很多资料,作为参考。下面就简单的说一说。

1、检测辅助模式的开启

之前提到过AccessibilityService类使用的是观察者模式,通过Binder机制在系统App1 view层->os->App2Service进行事件传递。由AccessibilityManagerService注册AccessibilityService,那如何检测到安装并启用辅助模式App2呢?系统提供了如下方法:


@Override
public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {synchronized (mLock) // We treat calls from a profile as if made by its parent as profiles// share the accessibility state of the parent. The call below// performs the current profile parent resolution.final int resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId);// The automation service is a fake one and should not be reported to clients as being installed - it really is not.UserState userState = getUserStateLocked(resolvedUserId);if (userState.mUiAutomationService != null) {List<AccessibilityServiceInfo> installedServices = new ArrayList<>();installedServices.addAll(userState.mInstalledServices);installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo);return installedServices;} return userState.mInstalledServices;}
}

@Overridepublic List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType,int userId) {List<AccessibilityServiceInfo> result = null;synchronized (mLock) {// We treat calls from a profile as if made by its parent as profiles// share the accessibility state of the parent. The call below// performs the current profile parent resolution.final int resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId);// The automation service can suppress other services.UserState userState = getUserStateLocked(resolvedUserId);if (userState.isUiAutomationSuppressingOtherServices()) {return Collections.emptyList();}result = mEnabledServicesForFeedbackTempList;result.clear();List<Service> services = userState.mBoundServices;while (feedbackType != 0) {final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));feedbackType &= ~feedbackTypeBit;final int serviceCount = services.size();for (int i = 0; i < serviceCount; i++) {Service service = services.get(i);// Don't report the UIAutomation (fake service)if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)&& (service.mFeedbackType & feedbackTypeBit) != 0) {result.add(service.mAccessibilityServiceInfo);}}}}return result;} 

这个方法remove了UiAutomationService,还是很贴心的。

返回值AccessibilityServiceInfo是一些我们使用的AccessibilityService的配置信息,包括packageNames(AccessibilityService 监控哪些package发出的Event),如下:

java


AccessibilityServiceInfo serviceInfo = new AccessibilityServiceInfo();
serviceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
serviceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
serviceInfo.packageNames = new String[]{"com.tencent.mm"};
serviceInfo.notificationTimeout=100;
setServiceInfo(serviceInfo); 

xml


<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeNotificationStateChanged|typeWindowStateChanged|typeWindowContentChanged|typeWindowsChanged"android:accessibilityFeedbackType="feedbackGeneric"android:accessibilityFlags="flagDefault|flagRequestEnhancedWebAccessibility"android:canRetrieveWindowContent="true"android:description="@string/app_name"android:notificationTimeout="100"android:packageNames="com.tencent.mm"android:canRequestEnhancedWebAccessibility="true"/> 

值得注意的是AccessibilityManagerService,属于com.android.server.accessibility包下,也就是系统内部类,不能直接用。

那应该怎么做呢?可以通过AccessibilityManager间接的操作AccessibilityManagerService,由上次分析系统源码可知,系统内部利用Binder机制调用了AccessibilityManagerService,拿到这个列表后遍历出自己的应用正在被谁监控或“辅助”了。

看一下怎么施工,向下看,


private List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(String targetPackage) { List<AccessibilityServiceInfo> result = new ArrayList<>(); AccessibilityManager accessibilityManager = (AccessibilityManager) getApplicationContext().getSystemService(Context.ACCESSIBILITY_SERVICE); if (accessibilityManager == null) { return result; } List<AccessibilityServiceInfo> infoList = accessibilityManager.getInstalledAccessibilityServiceList(); if (infoList == null || infoList.size() == 0) { return result; } for (AccessibilityServiceInfo info : infoList) { if (info.packageNames == null) { result.add(info);} else { for (String packageName : info.packageNames) { if (targetPackage.equals(packageName)) { result.add(info); } } }}return result;
} 

知识点:当info.packageNames为null时,表示监控所有包名。

2、干扰执行逻辑

AccessibilityServices在监控目标App发出的AccessibilityEvent时,对应的作出某些事件操作。比如,AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED。

某些微信红包插件会监控Notification的弹出,那么我们是否可以随意发送这样的Event出来,从而混干扰外挂插件的运行逻辑,比如


textView.sendAccessibilityEvent(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); 

大部分的外挂插件对特定类型的事件并不是特别感兴趣,他们仅在收到Event后检查页面上是否有某些特定的元素,从而决定是否进行下一步操作。

3、屏蔽文案检查

我们知道系统内部原理就是调用TextView的findViewsWithText方法,我们需要重写这个方法就可以


public class QTextView extends android.support.v7.widget.AppCompatTextView { @Override public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, int flags) {outViews.remove(this);}
} 

这样AccessibilityServices文案检查将会在这个View上失效。

4、屏蔽点击事件

AccessibilityServices执行点击事件,最终会去调用View的OnClickListener监听事件,那我们就利用onTouch代替onClick即可。

总结

检测并禁止相关App开启辅助模式;

重写TextView 的 findViewsWithText方法,屏蔽文案检查;

onTouch替换onClick,屏蔽View的点击事件;

随机发送AccessibilityEvent,使外挂执行逻辑错误;

通过PackageManager检测并禁止相关软件安装;

古人云:道高一尺,魔高一丈;下篇见Xposed相关文章。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值