FROM:http://blog.csdn.net/yiyaaixuexi/article/details/6803593
为Android应用程序读取/dev下设备而提权(一)
倘若应用程序需要对/dev/xxx进行读写操作,就需要提升其权限。提权方法不唯一,需要根据具体需求情况而选择。归根结底,终究都落到chmod 777 /dev/xxx 上,不同的是,chmod操作被执行在何时何地,在此做个分析总结。
内核启动后会执行/system/init,传说中的系统1号进程,init程序起初的任务是初始化,包括各种mkdir来构建文件系统,得到硬件信息建立设备节点,安装SIGCHLD信号来回收僵尸进程的资源,解析init.rc启动脚本等等,然后init程序变身为property_service来管理系统的权限。我们可以下手的地方有两处: device_init和init.rc
。
✿ init.rc
这个方案是大家用的比较多的,在其中添加chmod操作很简单不多说。
✿ device.c
这个方案用的比较少,先了解下device.c。
device_init在/system/core/init/device.c中,详细分析如下:
-
- device_init()
- {
- coldboot(fd,"/sys/class");
- coldboot(fd,"/sys/block");
- coldboot(fd,"/sys/devices");
- }
-
-
- do_coldboot()
- {
- if(fd>= 0) {
- write(fd,"add\n", 4);
- close(fd);
- handle_device_fd(event_fd);
- }
- }
-
-
- handle_device_fd()
- {
- if(!strcmp(uevent->action,"add")) {
- make_device(devpath,block, uevent->major, uevent->minor);
- return;
- }
- }
-
-
- make_device()
- {
- mode= get_device_perm(path,&uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- dev= (major << 8) | minor;
- mknod(path,mode, dev);
- chown(path,uid, gid);
- }
-
- get_device_perm()
- {
- if(get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) {
- returnperm;
- }elseif(get_device_perm_inner(devperms,path, uid, gid, &perm) == 0){
- returnperm;
- }else{
- …….
- }
-
-
- get_device_perm_inner
- {
- for(i= 0; perms[i].name; i++) {
-
- if(perms[i].prefix){
- if(strncmp(path,perms[i].name, strlen(perms[i].name)))
- continue;
- }else{
- if(strcmp(path,perms[i].name))
- continue;
- }
- *uid= perms[i].uid;
- *gid= perms[i].gid;
- *perm= perms[i].perm;
- return0;
- }
- }
-
- 这是devperms的具体内容
- structperms_ {
- char*name;
- mode_tperm;
- unsignedintuid;
- unsignedintgid;
- unsignedshortprefix;
- };
- staticstructperms_ devperms[] = {
- {"/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/full", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/random", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 },
- {"/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 },
-
-
- {"/dev/log/", 0662, AID_ROOT, AID_LOG, 1 },
-
-
- {"/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 },
- {"/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 },
- {"/dev/ttyMSM0", 0660, AID_BLUETOOTH, AID_BLUETOOTH, 0 },
- {"/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 },
- {"/dev/tty0", 0666, AID_ROOT, AID_SYSTEM, 0 },
- {"/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 },
- {"/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- {"/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 },
- {"/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 },
- {"/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 },
- {"/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 },
- {"/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 },
- {"/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 },
- {"/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 },
- {"/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 },
- {"/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 },
- {"/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 },
- {"/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
- {"/dev/htc-acoustic", 0640, AID_RADIO, AID_RADIO, 0 },
- {NULL, 0, 0, 0, 0 },
- };
✿ init.c
init.rc脚本和老版本android中的init.goldfish.rc脚本很早就被parse_config_file()函数解析将脚本内容分为几个段,early-init,init,early-boot,boot,和各个服务。然后在不同的时间点上执行各个段得命令或者开启各种服务。
init.c的一段节选:
- int main(intargc, char**argv)
- {
- ……
- mkdir("/dev",0755);
- mkdir("/proc",0755);
- mkdir("/sys",0755);
- mount("tmpfs","/dev", "tmpfs", 0, "mode=0755");
- mkdir("/dev/pts",0755);
- mkdir("/dev/socket",0755);
- mount("devpts","/dev/pts", "devpts", 0, NULL);
- mount("proc","/proc", "proc", 0, NULL);
- mount("sysfs","/sys", "sysfs", 0, NULL);
- … …
- INFO("readingconfig file\n");
- parse_config_file("/init.rc");
-
-
-
-
-
- action_for_each_trigger("early-init",action_add_queue_tail);
-
- drain_action_queue();
-
-
-
-
- ……
- INFO("deviceinit\n");
- device_fd= device_init();
-
- property_init();
-
- action_for_each_trigger("init",action_add_queue_tail);
- drain_action_queue();
-
- … …
- }
✿ 本节小结
device_init其实就是linux中的udev的一个简单的替代。把/sys/下的所有内核提供的设备都安排在/dev下创建设备节点。如果要改动/dev/一些设备的权限,可以把chmod 777写在init.rc中,但是要注意写的位置,不能太早执行,不能写在early-init段内,因为那时/dev/下的设备节点还没有被创建。
在devices.c中修改的方法隐藏的较深不容易被发现,但是如果init.rc内再次修改就可能把之前的修改覆盖掉。