AccessibilityService防护

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

一、检测辅助模式的开启

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

@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;
    }
}

@Override
    public 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,仍是很贴心的。android

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

javaapp

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);
复制代码

xmlide

<?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包下,也就是系统内部类,不能直接用。this

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

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

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时,表示监控全部包名。code

二、干扰执行逻辑

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

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

textView.sendAccessibilityEvent(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
复制代码

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

三、屏蔽文案检查

咱们知道系统内部原理就是调用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上失效。

四、屏蔽点击事件

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

总结

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

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

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

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

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

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

关注微信公众号,最新技术干货实时推送

image
相关文章
相关标签/搜索