为Android应用程序读取/dev下设备而提权(一)

来源:互联网 发布:子平算命软件 编辑:程序博客网 时间:2024/06/05 19:21

原文地址:http://blog.csdn.net/yiyaaixuexi/article/details/6803593

倘若应用程序需要对/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中,详细分析如下:

[cpp] view plaincopyprint?
  1. //分别遍历/sys/class /sys/block /sys/devices 
  2. device_init() 
  3.   coldboot(fd,"/sys/class"); 
  4.   coldboot(fd,"/sys/block"); 
  5.   coldboot(fd,"/sys/devices"); 
  6.     
  7. //后面有个递归 /sys下是内核生成的设备,这就相当于udev的作用 
  8. do_coldboot() 
  9.   if(fd>= 0) { 
  10.   write(fd,"add\n", 4); 
  11.   close(fd); 
  12.   handle_device_fd(event_fd); 
  13.   } 
  14.  
  15. //从socket里读出add处理 
  16. handle_device_fd()  
  17.   if(!strcmp(uevent->action,"add")) { 
  18.   make_device(devpath,block, uevent->major, uevent->minor); 
  19.   return
  20.   } 
  21.  
  22. //得到设备的相关信息创建设备节点 
  23. make_device()  
  24.   mode= get_device_perm(path,&uid, &gid) | (block ? S_IFBLK : S_IFCHR); 
  25.   dev= (major << 8) | minor; 
  26.   mknod(path,mode, dev); 
  27.   chown(path,uid, gid); 
  28.  
  29. get_device_perm() 
  30.   if(get_device_perm_inner(qemu_perms, path, uid, gid, &perm) == 0) { 
  31.   returnperm; 
  32.   }elseif(get_device_perm_inner(devperms,path, uid, gid, &perm) == 0){ 
  33.    returnperm; 
  34.   }else
  35.                 ……. 
  36.  
  37. //得到devperms结构体的信息 
  38. get_device_perm_inner 
  39. for(i= 0; perms[i].name; i++) { 
  40.  
  41. if(perms[i].prefix){ 
  42. if(strncmp(path,perms[i].name, strlen(perms[i].name))) 
  43. continue
  44. }else
  45. if(strcmp(path,perms[i].name)) 
  46. continue
  47. *uid= perms[i].uid; 
  48. *gid= perms[i].gid; 
  49. *perm= perms[i].perm; //权限位 
  50. return0; 
  51.  
  52. 这是devperms的具体内容 
  53. structperms_ { 
  54.    char*name; 
  55.    mode_tperm; 
  56.    unsignedintuid; 
  57.    unsignedintgid; 
  58.    unsignedshortprefix; 
  59. }; 
  60. staticstructperms_ devperms[] = { 
  61. {"/dev/null", 0666, AID_ROOT, AID_ROOT, 0 }, 
  62. {"/dev/zero", 0666, AID_ROOT, AID_ROOT, 0 }, 
  63. {"/dev/full", 0666, AID_ROOT, AID_ROOT, 0 }, 
  64. {"/dev/ptmx", 0666, AID_ROOT, AID_ROOT, 0 }, 
  65. {"/dev/tty", 0666, AID_ROOT, AID_ROOT, 0 }, 
  66. {"/dev/random", 0666, AID_ROOT, AID_ROOT, 0 }, 
  67. {"/dev/urandom", 0666, AID_ROOT, AID_ROOT, 0 }, 
  68. {"/dev/ashmem", 0666, AID_ROOT, AID_ROOT, 0 }, 
  69. {"/dev/binder", 0666, AID_ROOT, AID_ROOT, 0 }, 
  70.  
  71. /* logger should be world writable (for logging) but not readable*/ 
  72. {"/dev/log/", 0662, AID_ROOT, AID_LOG, 1 }, 
  73.  
  74. /*these should not be world writable */ 
  75. {"/dev/android_adb", 0660, AID_ADB, AID_ADB, 0 }, 
  76. {"/dev/android_adb_enable", 0660, AID_ADB, AID_ADB, 0 }, 
  77. {"/dev/ttyMSM0", 0660, AID_BLUETOOTH, AID_BLUETOOTH, 0 }, 
  78. {"/dev/alarm", 0664, AID_SYSTEM, AID_RADIO, 0 }, 
  79. {"/dev/tty0", 0666, AID_ROOT, AID_SYSTEM, 0 }, 
  80. {"/dev/graphics/", 0660, AID_ROOT, AID_GRAPHICS, 1 }, 
  81. {"/dev/hw3d", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 
  82. {"/dev/input/", 0660, AID_ROOT, AID_INPUT, 1 }, 
  83. {"/dev/eac", 0660, AID_ROOT, AID_AUDIO, 0 }, 
  84. {"/dev/cam", 0660, AID_ROOT, AID_CAMERA, 0 }, 
  85. {"/dev/pmem", 0660, AID_SYSTEM, AID_GRAPHICS, 0 }, 
  86. {"/dev/pmem_gpu", 0660, AID_SYSTEM, AID_GRAPHICS, 1 }, 
  87. {"/dev/pmem_adsp", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  88. {"/dev/pmem_camera", 0660, AID_SYSTEM, AID_CAMERA, 1 }, 
  89. {"/dev/oncrpc/", 0660, AID_ROOT, AID_SYSTEM, 1 }, 
  90. {"/dev/adsp/", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  91. {"/dev/mt9t013", 0660, AID_SYSTEM, AID_SYSTEM, 0 }, 
  92. {"/dev/akm8976_daemon",0640, AID_COMPASS, AID_SYSTEM, 0 }, 
  93. {"/dev/akm8976_aot", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
  94. {"/dev/akm8976_pffd", 0640, AID_COMPASS, AID_SYSTEM, 0 }, 
  95. {"/dev/msm_pcm_out", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  96. {"/dev/msm_pcm_in", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  97. {"/dev/msm_pcm_ctl", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  98. {"/dev/msm_mp3", 0660, AID_SYSTEM, AID_AUDIO, 1 }, 
  99. {"/dev/smd0", 0640, AID_RADIO, AID_RADIO, 0 }, 
  100. {"/dev/qmi", 0640, AID_RADIO, AID_RADIO, 0 }, 
  101. {"/dev/qmi0", 0640, AID_RADIO, AID_RADIO, 0 }, 
  102. {"/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 }, 
  103. {"/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 }, 
  104. {"/dev/htc-acoustic", 0640, AID_RADIO, AID_RADIO, 0 }, 
  105. {NULL, 0, 0, 0, 0 }, 
  106. }; 

✿ init.c

       init.rc脚本和老版本android中的init.goldfish.rc脚本很早就被parse_config_file()函数解析将脚本内容分为几个段,early-init,init,early-boot,boot,和各个服务。然后在不同的时间点上执行各个段得命令或者开启各种服务。

  
init.c的一段节选:
  
[cpp] view plaincopyprint?
  1. int main(intargc, char**argv) 
  2.   …… 
  3.   mkdir("/dev",0755);  
  4.   mkdir("/proc",0755); 
  5.   mkdir("/sys",0755); 
  6.   mount("tmpfs","/dev","tmpfs", 0, "mode=0755"); 
  7.   mkdir("/dev/pts",0755); 
  8.   mkdir("/dev/socket",0755); 
  9.   mount("devpts","/dev/pts","devpts", 0, NULL); 
  10.   mount("proc","/proc","proc", 0, NULL); 
  11.   mount("sysfs","/sys","sysfs", 0, NULL); 
  12.   … … 
  13.   INFO("readingconfig file\n"); 
  14.   parse_config_file("/init.rc");  
  15. //调用parse_config解析init.rc脚本 
  16. //经过解析,init.rc的内容就被分为多少个段,被串在action_list链表中。 
  17. //on开头的都是action类型的段,比如init段,init段用一个结构体struct action表示,其中name是init, 
  18. //所有这个段内的命令,都被串在commands链表中。 
  19.  
  20.   action_for_each_trigger("early-init",action_add_queue_tail);  
  21. //遍历action_list链表,查找name是early-init的那个action,将这个节点放在action_queue的尾部。 
  22.   drain_action_queue(); 
  23. //将action_queue尾部的节点遍历,然后删除。 
  24. //就相当于遍历name是early-init的action节点内的commands链表。 
  25. //就是在执行init.rc脚本中onearly-init段内的所有命令。 
  26.  
  27. …… 
  28.   INFO("deviceinit\n"); 
  29.   device_fd= device_init(); //常见必要的设备节点 
  30.  
  31.   property_init();//init 以后的任务就是proper_service 
  32.  
  33.   action_for_each_trigger("init",action_add_queue_tail);//将init段,加入action_queue 
  34.   drain_action_queue();// 执行init段得命令 
  35.  
  36. … … 

✿ 本节小结

      device_init其实就是linux中的udev的一个简单的替代。把/sys/下的所有内核提供的设备都安排在/dev下创建设备节点。如果要改动/dev/一些设备的权限,可以把chmod 777写在init.rc中,但是要注意写的位置,不能太早执行,不能写在early-init段内,因为那时/dev/下的设备节点还没有被创建。
      在devices.c中修改的方法隐藏的较深不容易被发现,但是如果init.rc内再次修改就可能把之前的修改覆盖掉。