1.功能
以root身份运行命令,可以在未root的情况下查看某个(debug模式的)应用的内部信息(沙盒文件夹)
2.介绍
非root手机run-as命令获取debug版本apk里面的数据(shared_prefs文件、lib下面的so、数据库文件)
在没有root过的手机中,用户权限是无法查看很多信息的,包括各个应用的沙盒
而run-as就向开发者提供了未root情况下访问沙盒信息的权限
执行run-as + 包名,就可以直接以root权限进入该应用的沙盒中查看包括数据库、xml、各种信息文件
adb shell
run-as package-name
Android7.1.2(Nexus5手机已Root)
Android10(Redmi 9A手机未Root)
ls -al
3.条件
应用需为debug模式,即AndroidManifest.xml文件中,android:debugable需要为true
android:debuggable="true"
如果签名了,并且指定设置了android:debuggable="false",将无法使用该命令
android:debuggable="false"
4.原理
Linux系统下除了rwx三个基本权限以外,还有特殊的s(setuid)权限和g(setgid)权限
s权限可以使得低权限用户以该程序的所有者的权限去执行命令
在某些情况下可以提供极大的方便,例如普通用户想要修改密码或者一些关键程序,就可以通过root用户设定好的特定程序来在规则内修改本无法修改的文件
但是s权限也具有相当程度的危险性,当该程序存在漏洞,最坏的情况下具备任意代码执行的能力时,则说可以利用其提权,即普通用户可以通过它得到完全的root权限
回到正题
run-as程序正是通过s权限使得普通用户可以在满足条件(应用为debug模式时、操作目录仅在应用沙盒下)时具备root权限
5.延伸
除了提权以外,s权限还可以用来降权
root用户可以更改文件的拥有者,从而可以通过s权限任意更改程序执行时的权限
在安卓系统中,所有进程都是由zygote进程fork出来的,如果不降权的话则所有进程都与父进程相同、具备了root权限,这显然是不安全的。因此zygote通过forkAndSpecializeCommon函数来进行降权处理,使得子进程具备可控的权限
6.补充
/data/data/package/lib目录是可以直接访问的,adb shell后虽然无法读取/data目录,但是可以直接访问这个目录下的文件,可以通过run-as命令看得出其权限与其他目录的权限是不同的,为system权限,这为多apk共享so提供了便利。
关于共享数据也可以研究/data/data/package/files,使用openFileOutput的第二个参数来指定访问权限
函数声明:
FileOutputStream openFileOutput (String name, int mode)
作用:
可以方便地在手机中创建文件,并返回文件输出流,用于对文件做写入操作。
openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录。
openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为:
Context.MODE_PRIVATE = 0
Context.MODE_APPEND = 32768
Context.MODE_WORLD_READABLE = 1
Context.MODE_WORLD_WRITEABLE = 2
Context.MODE_PRIVATE
为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中,可以使用Context.MODE_APPEND。
Context.MODE_APPEND
模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE
用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE
表示当前文件可以被其他应用读取;
MODE_WORLD_WRITEABLE
表示当前文件可以被其他应用写入。
如果希望文件被其他应用读和写,可以传入:
openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
Android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。
(1).判读文件是否存在
public boolean existsFile(String fileName){
String path = this.getFilesDir().getPath()+"//";
File file = new File(path+fileName);
if(file.exists()){
return true;
}
return false;
}
(2).读取文件
public String readFile(String fileName) throws IOException{
FileInputStream fis = context.openFileInput(fileName);
int len = fis.available();
byte []buffer = new byte[len];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((fis.read(buffer))!=-1){
baos.write(buffer);
}
byte []data = baos.toByteArray();
baos.close();
fis.close();
return new String(data);
}
public void load() {
try {
FileInputStream inStream=this.openFileInput(“a.txt”);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int length=-1;
while((length=inStream.read(buffer))!=-1) {
stream.write(buffer,0,length);
}
stream.close();
inStream.close();
text.setText(stream.toString());
Toast.makeText(MyActivity.this,”Loaded”,Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e){
return ;
}
}
返回文件输入流,用于对文件的读操作
FileInputStream openFileInput (String name)
对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。
Activity还提供了getCacheDir()和getFilesDir()方法:
getCacheDir()方法用于获取/data/data/<package name>/cache目录
getFilesDir()方法用于获取/data/data/<package name>/files目录
(3).把文件放入SD卡
使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,可以把它存放在SDCard.
在程序中访问SDCard,你需要申请访问SDCard的权限。在AndroidManifest.xml中加入访问SDCard的权限,如下所示:
<!– 在SDCard中创建与删除文件权限 –>
<uses-permission android:name=”android.permission.MOUNT_UNMOUNT_FILESYSTEMS”/>
<!– 往SDCard写入数据权限 –>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>
访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限,要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录
File saveFile = new File(sdCardDir, “a.txt”);
FileOutputStream outStream = new FileOutputStream(saveFile);
outStream.write(“test”.getBytes());
outStream.close();
}
Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。
Environment.getExternalStorageDirectory()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写:
File sdCardDir = new File(“/sdcard”); //获取SDCard目录
File saveFile = new File(sdCardDir, “itcast.txt”);
//上面两句代码可以合成一句:
File saveFile = new File(“/sdcard/a.txt”);
FileOutputStream outStream = new FileOutputStream(saveFile);
outStream.write(“test”.getBytes());
outStream.close();
(4).保存文件
public void saveFile(String fileName, String str) throws IOException{
FileOutputStream fos = context.openFileOutput(fileName, Activity.MODE_APPEND);
byte[]bytes=str.getBytes();
fos.write(bytes);
fos.flush();
fos.close();
}
原文链接
如果对文章感兴趣,可以扫一扫微信二维码关注作者的微信公众号,后续会推送更多干货文章,感谢您的支持。