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
相關文章
相關標籤/搜索