首页 > 代码库 > 从”茄子快传”看应用程序如何获取手机已安装程序的apk文件

从”茄子快传”看应用程序如何获取手机已安装程序的apk文件

       ”茄子快传”是联想开发的一款近距离文件共享软件,它通过wifi-direct(速度飞快,不需要联网)或者普通的网络(速度慢)在不同手机间传递文件。不知为何,它就火了起来,火的也飞快。其中,共享传输已安装程序文件apk这一功能引起我强烈的兴趣。



        我们知道android对每个应用的权限做了很苛刻的控制,每个应用程序有自己的用户id,每个应用程序只能访问自己的数据,比如程序com.android.calculator计算器程序只被允许访问/data/data/com.android.calculator目录下的数据,且该程序的所有数据也都保存在该目录下。同时当程序被安装时,系统会将安装文件apk拷贝到/data/app目录下。那茄子快船作为普通的程序,它怎么具有读取/data/app下apk文件的权限的呢?如果它不是读取该目录下的apk文件,那程序的安装文件apk它是从哪里获取到的呢?

         于是,我开始充分发挥主观能动性,开始不停思考它的实现方法,并有了如下想法和实践。


实现原理分析及实践


1)  实现方式一:

        一开始我很坚定的认为茄子快船肯定不是读取手机里的程序的安装文件apk。我认为它只不过读取了系统所有已安装程序的信息,然后根据程序的包名在网络服务器上搜索对应的安装文件(apk文件)并下载,然后再通过网络传送给其他手机。

       为了验证这一猜测,我猜想只要我断了网络,它自然没法做程序搜索,那么肯定就没法传送文件了。于是,我做了如下实验:

我断掉自己手机的所有网络(2g/wifi),然后再使用这个功能选择某一程序并选择发送给其他手机,结果发现它仍然工作。

        于是我接着猜测,这个apk文件很有可能在程序安装的时候就从服务器下载到茄子快船程序的目录里了,因此在发送的时候它不再需要网络了。于是我又做了另外一个实验:

         我断掉我所有的网络,然后通过adb安装某一程序,这样在安装的过程中,茄子快船肯定是没法从网络上下载相应的apk文件的。但是出人意料的是,茄子快船仍然成功传送了我刚刚安装的程序对应的安装文件。

2)  最后我不得不相信它确实是通过读取/data/app下的apk文件来传送安装程序的。

          那我开始想了,难道/data/app下的文件本身确实是可读的。我不信邪,我开始查看这些文件的权限信息。           于是我又开始了下面的实验。为了模拟一般程序的权限,我用shell用户来执行读取/data/app/下的文件以      验证普通程序是否有相关权限。

itleaks@Itleaks/tmp$ adb shell
1|shell@htc:/ $ ls /data -al                                                
opendir failed, Permission denied
shell@htc:/ $ ls /data/app -al
opendir failed, Permission denied
#没有权限
1|shell@htc:/ $

          从上面可以看出一般的程序应该是没法直接读取/data/app下面的文件啊,不对啊?只好出绝招了,我接着又使用root用户来查看目录的具体权限:

1|shell@htc:/ $ su root
root@htc:/ # ls /data -al
ls /data -al
drwxrwx--x system   system            2014-06-19 20:40 app

           到此,我终于明白了,原来/data/app目录对于其他用户具备-x权限。也就是说普通程序可以进入该目录,但是没法读取该目录文件里的内容,即没法查询该目录下有哪些文件。这也是为什么我们执行ls /data/app –al失败的原因,因为这个命令会读取目录文件,自然需要该目录对其他用户开放-r权限。在-x权限下,只需该目录下的文件对第三方程序开发-r权限,那么程序就可通过具体文件名称来读取该目录的对应文件。于是迫不及待的想看该目录下的文件权限属性。

root@htc:/ # cd /data/app
cd /data/app
root@htc:/data/app # ls -al
ls -al
-rw-r--r-- system   system    5784942 2014-05-18 15:22 cn.lvye.hd-1.apk
-rw-r--r-- system   system   16056547 2014-05-16 21:11 cn.whonow.whonow-1.apk

          果然,目录下的apk对于其他用户有-r权限。于是我重新模拟普通程序用户的权限开始如下的实验。

root@htc:/data/app # exit
exit
#回到shell用户
shell@htc:/ $ ls /data/app
opendir failed, Permission denied
shell@htc:/ $ cd /data/app
#进入/data/app目录成功
shell@htc:/data/app $ cd -
/
1|shell@htc:/ $ ls /data/app/cn.lvye.hd-1.apk -al
-rw-r--r-- system   system    5784942 2014-05-18 15:22 cn.lvye.hd-1.apk
#读取apk文件成功

          从上面可以看出,shell用户已经成功读取到cn.lvye.hd-1.apk文件的信息。但是还有一个问题,我们刚刚是通过root用户来查看/data/app目录下的apk文件的名字的,对于普通用户来说,它是没法知道/data/app下有哪些文件的,那它是如何知道某一个程序的安装文件名的呢?其实这个很简单,已安装程序的PackageInfo.sourceDir信息会指明该程序的安装程序名称及路径。具体获取代码如下:

public class MainActivity extends Activity {

	private static final String TAG = "Itleaks test";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		readFirstApkFile();
	}

	private void readFirstApkFile() {
		// TODO Auto-generated method stub
        List<PackageInfo> installedList = this.getPackageManager().getInstalledPackages(0);
        int installedListSize = installedList.size();
        ApplicationInfo firstApplicationInfo = null;
        for(int i = 0; i < installedListSize; i++) {
            PackageInfo info = installedList.get(i);
            ApplicationInfo aInfo = info.applicationInfo;
            Log.d(TAG, "application source dir " + aInfo.sourceDir); 
            if (firstApplicationInfo == null) {
            	firstApplicationInfo = aInfo;
            }
        }
        File file = new File(firstApplicationInfo.sourceDir);
        if (!file.exists()) {
        	Log.e(TAG, "package:" + firstApplicationInfo.packageName
        			+ " Apk file " + firstApplicationInfo.sourceDir + " doesn't exist");
        } else {
        	FileInputStream in = null;
			try {
				in = new FileInputStream(file);
				int size;
				try {
					size = in.available();
		        	Log.d(TAG, "Apk file " + firstApplicationInfo.sourceDir + " size:" + size);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
	}
}

         对于乐视lvye这个程序,其sourceDir为/data/app/cn.lvye.hd-1.apk,有了这个文件路径,普通程序就可以通过一般的文件读取操作来读取该文件了。



附录:


         大家可以在github上下载到文中的源码及apk文件:

         https://github.com/itleaks/apkfileshare


/********************************

* 本文来自博客  “爱踢门”

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/


附录:


         大家可以在github上下载到文中的源码及apk文件:

         https://github.com/itleaks/apkfileshare


/********************************

* 本文来自博客  “爱踢门”

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/