Android Accessibility(辅助功能) 安全相关问题

转载自:http://www.tuicool.com/articles/bYRZJn




对于那些由于视力、听力或其它身体原因导致不能方便使用Android智能手机的用户,Android提供了Accessibility功能和服务帮助这些用户更加简单地操作设备,包括文字转语音、触觉反馈、手势操作、轨迹球和手柄操作。开发者可以搭建自己的Accessibility服务,这可以加强可用性,例如声音提示,物理反馈,和其他可选的操作模式。

随着Android版本的不断升级,Android Accessibility功能也越来越强大,Android 4.0版本以前,系统辅助服务功能比较单一,仅仅能过单向获取窗口元素信息,比如获取输入框用户输入内容。到Android 4.1版本以后,系统辅助服务增加了与窗口元素的双向交互,此时可以通过辅助功能服务操作窗口元素,比如点击按钮等。

由于系统辅助服务能够实时获取您当前操作应用的窗口元素信息,这有可能给你带来隐私信息的泄露风险,比如获取非密码输入框的输入内容等。同时通过辅助功能也可以模拟用户自动化点击应用内元素,也会带来一定的安全风险。

本文实现了一种通过系统辅助服务完成应用的自动安装、卸载、强行停止的功能。

1、AndroidManifest.xml文件配置自己实现的MyAccessibilityService服务。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.jack.accessibility"
  android:versionCode="1"
  android:versionName="1.0" >
  <uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="18" />
  <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
      android:name="com.jack.accessibility.MainActivity"
      android:label="@string/app_name" >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <service android:label="@string/acc_service_name" android:name=".MyAccessibilityService" 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/phone_accessibility" />
    </service>
  </application>
</manifest>

2、在res/xml/phone_accessibility.xml配置相应的参数信息。

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service android:description="@string/accessibility_service_description"
  android:accessibilityEventTypes="typeAllMask" 
  android:accessibilityFeedbackType="feedbackGeneric" 
  android:notificationTimeout="100" 
  android:accessibilityFlags="" 
  android:canRetrieveWindowContent="true"
  xmlns:android="http://schemas.android.com/apk/res/android" />

3、MainActivity实现安装、卸载、强行停止动作的发起。

package com.jack.accessibility;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.view.View;
import android.app.Activity;
import android.content.Intent;

public class MainActivity extends Activity {
    
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    this.findViewById(R.id.activeButton).setOnClickListener(new View.OnClickListener() {
      
      @Override
      public void onClick(View arg0) {
        // TODO Auto-generated method stub
        Intent killIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
        startActivity(killIntent);
      }
    });
    
    this.findViewById(R.id.installButton).setOnClickListener(new View.OnClickListener() {
      
      @Override
      public void onClick(View arg0) {
        // TODO Auto-generated method stub
        MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_INSTALL_APP;
        String fileName = Environment.getExternalStorageDirectory() + "/test.apk"; 
        File installFile = new File(fileName);
        if(installFile.exists()){
          installFile.delete();
        }
        try {
          installFile.createNewFile();
          FileOutputStream out = new FileOutputStream(installFile);
          byte[] buffer = new byte[512];
          InputStream in = MainActivity.this.getAssets().open("test.apk");
          int count;
          while((count= in.read(buffer))!=-1){
            out.write(buffer, 0, count);
          }
          in.close();
          out.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        Intent intent = new Intent(Intent.ACTION_VIEW); 
        intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive"); 
        startActivity(intent);
        
      }
    });
    this.findViewById(R.id.uninstallButton).setOnClickListener(new View.OnClickListener() {
      
      @Override
      public void onClick(View arg0) {
        // TODO Auto-generated method stub
        MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_UNINSTALL_APP;
        Uri packageURI = Uri.parse("package:com.example.test"); 
        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI); 
        startActivity(uninstallIntent); 
      }
    });
    this.findViewById(R.id.killAppButton).setOnClickListener(new View.OnClickListener() {
      
      @Override
      public void onClick(View arg0) {
        // TODO Auto-generated method stub
        MyAccessibilityService.INVOKE_TYPE = MyAccessibilityService.TYPE_KILL_APP;
        Intent killIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri packageURI = Uri.parse("package:com.example.test"); 
        killIntent.setData(packageURI);
        startActivity(killIntent);
      }
    });
  }
}

4、MyAccessibilityService中通过自动化点击实现应用安装、卸载、强行停止功能。

package com.jack.accessibility;

import java.util.List;

import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.util.Log;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

@SuppressLint("NewApi")
public class MyAccessibilityService extends AccessibilityService {

  public static int INVOKE_TYPE = 0;
  public static final int TYPE_KILL_APP = 1;
  public static final int TYPE_INSTALL_APP = 2;
  public static final int TYPE_UNINSTALL_APP = 3;
  
  public static void reset(){
    INVOKE_TYPE = 0;
  }

  @Override
  public void onAccessibilityEvent(AccessibilityEvent event) {
    // TODO Auto-generated method stub
    this.processAccessibilityEnvent(event);
  }

  private void processAccessibilityEnvent(AccessibilityEvent event) {

    Log.d("test", event.eventTypeToString(event.getEventType()));
    if (event.getSource() == null) {
      Log.d("test", "the source = null");
    } else {
      Log.d("test", "event = " + event.toString());
      switch (INVOKE_TYPE) {
      case TYPE_KILL_APP:
        processKillApplication(event);
        break;
      case TYPE_INSTALL_APP:
        processinstallApplication(event);
        break;
      case TYPE_UNINSTALL_APP:
        processUninstallApplication(event);
        break;				
      default:
        break;
      }						
    }
  }

  @Override
  protected boolean onKeyEvent(KeyEvent event) {
    // TODO Auto-generated method stub
    return true;

  }

  @Override
  public void onInterrupt() {
    // TODO Auto-generated method stub

  }

  private void processUninstallApplication(AccessibilityEvent event) {
    
    if (event.getSource() != null) {
      if (event.getPackageName().equals("com.android.packageinstaller")) {
        List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("确定");
        if (ok_nodes!=null && !ok_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<ok_nodes.size(); i++){
            node = ok_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
              node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
          }

        }
      }
    }

  }

  private void processinstallApplication(AccessibilityEvent event) {
    
    if (event.getSource() != null) {
      if (event.getPackageName().equals("com.android.packageinstaller")) {			
        List<AccessibilityNodeInfo> unintall_nodes = event.getSource().findAccessibilityNodeInfosByText("安装");
        if (unintall_nodes!=null && !unintall_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<unintall_nodes.size(); i++){
            node = unintall_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
              node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
          }
        }
        
        List<AccessibilityNodeInfo> next_nodes = event.getSource().findAccessibilityNodeInfosByText("下一步");
        if (next_nodes!=null && !next_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<next_nodes.size(); i++){
            node = next_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
              node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
          }
        }
        
        List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("打开");
        if (ok_nodes!=null && !ok_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<ok_nodes.size(); i++){
            node = ok_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
              node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
          }	
        }


      }
    }

  }

  private void processKillApplication(AccessibilityEvent event) {
    
    if (event.getSource() != null) {
      if (event.getPackageName().equals("com.android.settings")) {
        List<AccessibilityNodeInfo> stop_nodes = event.getSource().findAccessibilityNodeInfosByText("强行停止");
        if (stop_nodes!=null && !stop_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<stop_nodes.size(); i++){
            node = stop_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button")) {
              if(node.isEnabled()){
                 node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
              }
            }
          }
        }

        List<AccessibilityNodeInfo> ok_nodes = event.getSource().findAccessibilityNodeInfosByText("确定");
        if (ok_nodes!=null && !ok_nodes.isEmpty()) {
          AccessibilityNodeInfo node;
          for(int i=0; i<ok_nodes.size(); i++){
            node = ok_nodes.get(i);
            if (node.getClassName().equals("android.widget.Button")) {
              node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
              Log.d("action", "click ok");
            }
          }

        }
      }
    }
  }

}
完整DEMO下载地址:  http://download.csdn.net/detail/jiazhijun/8251277

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值