爱测未来移动-Android静默安装

静默安装,就是apk在后台悄悄地安装,用于解决android自动嵌入式智能设备远程自动升级问题,安装过程无需人为操作。很多流氓软件喜欢干。但从现在的情况看,只有root了的手机,或者你能搞到手机厂商的签名,才能静默安装。

关于静默安装,基本上有两种情况。
1.root情况下静默安装
2.非root下面静默安装


root情况静默安装


  1.    调用pm指令,下面就是调用pm指令(pminstall -r)把/sdcard/haha.apk安装掉。


protectedvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

runShellCommand("pminstall -r  /sdcard/haha.apk")//执行命令

}

privatevoidrunShellCommand(String command){

Processprocess = null;

BufferedReader bufferedReader = null;

StringBuilder mShellCommandSB =new StringBuilder();

Log.d("wenfeng""runShellCommand :" + command);

mShellCommandSB.delete(0, mShellCommandSB.length());

String[] cmd = newString[] { "/system/bin/sh""-c", command }; //调用bin文件

try {

byte b[] = newbyte[1024];

process =Runtime.getRuntime().exec(cmd);


bufferedReader = new BufferedReader(newInputStreamReader(

process.getInputStream()));

Stringline;

while ((line = bufferedReader.readLine()) != null) {

mShellCommandSB.append(line);

}

Log.d("wenfeng""runShellCommand result : " + mShellCommandSB.toString());

process.waitFor();

catch (IOException e) {

e.printStackTrace();

catch (InterruptedException e) {

e.printStackTrace();

} finally {

if(bufferedReader != null) {

try {

bufferedReader.close();

catch (IOException e) {

}

}

if (process != null) {

process.destroy();

}

}

}

2.   调用cp指令,把apk拷贝到data/app目录下,把上面的runShellCommand("pminstall -r /sdcard/haha.apk")替换成下面这句。然后用户下次重启时,apk就会自动安装。



runShellCommand("cp /sdcard/haha.apk /data/app")

非root下面静默安装

调用辅助功能,跟抢红包原理差不多。这里也就是使用了AccessibilityService,其实这种方式并不算严格的静默安装,因为用户可以看到安装的界面。很多应用商店都用到这种方式批量安装apk,下载后自动弹出安装界面,然后自动帮你点击安装。就能抢红包一样,自动打开红包页面,自动点击红包的道理一样一样的。
这个辅助功能最开始google设计是用于残疾人的,让他们更加方便的使用手机。一个应用要获取辅助功能,首先要在设置里面授权。


爱测未来移动-Android静默安装


  1.   定义一个类继承AccessibilityService,重写方法onAccessibilityEvent(AccessibilityEventevent),通过onAccessibilityEvent这个方法我们可以获取屏幕状态变化,屏幕内容变化以及通知栏的变化,

    爱测未来移动-Android静默安装



我们可以根据相应的变化做出我们的处理,屏幕滑动,或者点击相应的Button按钮。


爱测未来移动-Android静默安装

爱测未来移动-Android静默安装


2.   反射调用PackageManage
当我们选择手动安装应用时,会跳转到应用安装界面,这个界面就是系统的PackageInstaller 提供,专门用来让用户有感知地安装应用。


Itent intent = newIntent(Intent.ACTION_VIEW);

ri uri = Uri.fromFile(newFile("/sdcard/news.apk")));

intent.setDataAndType(uri, "application/vnd.android.package-archive");

startActivity(intent);


分析 PackageInstaller 的源码,我们发现它会通过PackageManager 调用installPackage 方法,这是个隐藏的抽象方法,实现类是ApplicationPackageManager。主要看一下四个参数:packageURI 就是 apk 的路径;observer 是安装的监听器,应用安装完成时会被回调,不能为null;flags 是标志位,指定安装的参数;installersPackageName表示可选的安装来源,比如应用宝之类的。


publicabstractvoidinstallPackage(UripackageURI, PackageInstallObserver observer, int flags, StringinstallerPackageName);


ApplicationPackageManager 里面 mPM 是一个IPackageManager 类型的对象,它会执行具体的安装任务


try {

mPM.installPackage(originPath,observer.getBinder(), flags, installerPackageName, verificationParams,null);

catch(RemoteException ignored) {

}


ContextImpl 的getPackageManager 方法,通过 ActivityThread 获取 IPackageManager 对象用来构造ApplicationPackageManager,然后返回 ApplicationPackageManager。

ActivityThread 的getPackageManager 方法,其实就是获取系统服务的过程。

publicstatic IPackageManager getPackageManager() {

        if (sPackageManager != null) {

           //Slog.v("PackageManager", "returning cur default =" + sPackageManager);

            return sPackageManager;

        }

        IBinder b =ServiceManager.getService("package");

        //Slog.v("PackageManager","default service binder = " + b);

        sPackageManager =IPackageManager.Stub.asInterface(b);

        //Slog.v("PackageManager","default service = " + sPackageManager);

        return sPackageManager;

}


通过以上分析,我们通过 PackageManager 调用 installPackage 方法就行了,下面看代码:


publicstatic boolean silentInstall(PackageManager packageManager, String apkPath) {

        Class<?> pmClz =packageManager.getClass();

        try {

            if (Build.VERSION.SDK_INT >= 21){

                Class<?> aClass =Class.forName("android.app.PackageInstallObserver");

                Constructor<?>constructor = aClass.getDeclaredConstructor();

               constructor.setAccessible(true);

                Object installObserver =constructor.newInstance();

                Method method =pmClz.getDeclaredMethod("installPackage", Uri.class, aClass,int.class, String.class);

                method.setAccessible(true);

                method.invoke(packageManager,Uri.fromFile(new File(apkPath)), installObserver, 2, null);

            } else {

                Method method =pmClz.getDeclaredMethod("installPackage", Uri.class,Class.forName("android.content.pm.IPackageInstallObserver"),int.class, String.class);

                method.setAccessible(true);

                method.invoke(packageManager,Uri.fromFile(new File(apkPath)), null, 2, null);

            }

            return true;

        } catch (Exception e) {

            log.error(e);

        }

        return false;

    }


然而,这个方法介绍了那么多,其实这种方式是不可行的,原因是:


1.installPackageAsUser会远程调用PackageManagerService进行安装,但安装前需要校验权限,只有System权限以上才能通过校验。所以为了编译System权限的app,需要在AndroidManifest增加一句android:sharedUserId="android.uid.system"。


2.但你以为你这个System权限的app可以安装到现实手机中吗?不可能的,系统在安装AndroidManifest包含android:sharedUserId="android.uid.system"的app时,都会首先看下app的签名。app签名不对直接就安装失败的。除非,你能搞到手机厂家的签名!!!!签名这个可是重大机密,泄露可是要出人命的。



2017.07.08测试技术嘉年华火热报名中

国际著名安全机构OWASP、前惠普高级性能工程师大牛就要来讯飞啦

还不快来报名!

报名地址:https://www.sojump.hk/jq/14382135.aspx

嘉年华官网:http://itest.iflytek.com/

爱测未来公众号:itest_forever

爱测未来移动-Android静默安装

CSDN:http://blog.csdn.net/itest_2016

QQ群:274166295(爱测未来2群)、610934609(爱测未来3群)

会场地址:合肥市望江西路666号科大讯飞语音产业基地A1#201会场

时间:2017.07.08