android su源码
2015-06-26 17:10
459 查看
android su 通过源码编译出来的;
文件位置: $android/system/extras/su/
Android.mk:
LOCAL_MODULE_TAGS 为debug 表示,只有debug版本才编译;
如果希望在其他,参看:http://blog.csdn.net/passerbysrs/article/details/46650113
再看源码:
来看看uid的定义:
system/core/include/private/android_filesystem_config.h:
一些预备知识:
getpwnam() 用于获取用户登录相关信息
getuid()用来取得执行目前进程的用户识别码
execlp
int execlp(const char * file,const char * arg,...,(char *)0);
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。
setgid和setuid :
参看http://blog.chinaunix.net/uid-793704-id-2545508.html
http://blog.csdn.net/passerbysrs/article/details/46650731
目的:setuid 和setgid是让普通用户可以以root用户的角色运行只有root帐号才能运行的程序或命令。
内核检查一个进程是否具有访问某权限时,是使用进程的有效用户 ID 来进行检查的;
UID和GID这样的标识符会影响文件的所有权和访问许可,以及向其它进程发送信号的能力。这些属性统称为凭证。
每个进程都有两对ID ——真实的和有效的。当一个用户登录的时候,login程序会把两对ID设置成密码数据库(/etc/passwd文件,或某些如Sun Microsystems的NIS之类的分布式机制)中指定的UID和GID。当一个进程fork的时候,子进程将从父进程那儿继承它的凭证。
有效UID和有效GID印象文件的创建和访问。在创建文件的时候,内核将文件的所有者属性设置成创建进程的有效UID和有效GID。在访问文件的时候,内核使用进程的有效UID和GID来判断它是否能够访问该文件。真实UID和真实GID标识进程的真实所有者,会影响到发送信号的权限。对于一个没有超级用户权限的进程来说,仅当它的真实或有效UID于另一个进程的真实UID匹配时它才能向那个进程发送信号。
setuid系统调用的语法是 setuid(uid) ,其中,uid是新的用户ID,该系统调用的结果取决于有效用户ID的当前值。
如果调用进程的有效用户ID是超级用户,内核会把进程表以及u区中的真实和有效用户ID都设置成uid。
如果调用进程的有效用户ID不是超级用户,仅当uid等于真实用户ID或保存用户ID时,内核才会把u区中的有效用户ID设置成uid。
否则,该系统调用将返回错误。
一般来说,一个进程会在fork系统调用期间从父进程那儿继承它的真实和有效用户ID,这些数值即使经过exec系统调用也会保持不变。
在 root 下,实际用户 ID 和有效用户 ID 均能被设为 setuid() 修改。
比如我们用普通用户运行passwd命令来更改自己的口令,实际上最终更改的是/etc/passwd文件。
我们知道/etc/passwd文件是用户管理的配置文件,只有root权限的用户才能更改。
作为普通用户如果修改自己的口令通过修改/etc/passwd肯定是不可完成的任务,但是不是可以通过一个命令来修改呢。答案是肯定的,作为普通用户可以通过passwd 来修改自己的口令。这归功于passwd命令的权限。我们来看一下;
因为/usr/bin/passwd 文件已经设置了setuid 权限位(也就是r-s--x--x中的s),所以普通用户能临时变成root,间接的修改/etc/passwd,以达到修改自己口令的权限。
setuid和setgid的实例应用;
我们想让一个普通用户beinan拥有root用户拥有超级rm删除权限,我们除了用su或sudo 临时切换到 root身份操作以外,还能怎么做呢???
rm: 无法删除 “beinantest.txt”: 权限不够
那我们怎么才能让beinan 这个普通用户也拥有root超级的rm 删除功力呢?
我们只是设置了rm的setuid位,让普通用户在rm指令上有超级root的删除超级权力。
通过这个例子,我们应该能明白setuid和setgid位的应用了,如同前面所说,让普通用户超越本身的能力,让普通用户能执行只有root才能执行的命令。在这一点,我们要和su和sudo 区分开来。请参见su和sudo的文档:《Linux 系统中的超级权限的控制》
开始分析:
a. 执行用户权限识别
getuid() 之后判定当前执行用户的uid是否是root 或者debug shell user
b. 判定参数
如果 argc < 2 : 表示只执行了su ; 那么就将uid和gid都设为0,即Root账户的uid与gid
否则的话: 比如su ryan , 则通过getpwnam() 获取ryan的相关信息,并将ryan的uid和gid取出来保存;
c. setgid 和setuid
假设当前进入系统后的用户是alex, 在./下有个cmd 二进制,它的创建有拥有者是ryan;
alex是没有权限执行的;
因此必须用如下方法
比如system/xbin/su ryan cmd others
argc[0]: su
argc[1]: ryan
argc[2]: cmd
argc[3]: others
先看看init.rc的权限:
setuid = chmod u+s xxx # 设置setuid权限
setgid = chmod
g+s xxx # 设置setgid权限
首先获取ryan的 uid和gid
然后通过setuid和setgid将ryan的uid和gid设置到进程中;
这个时候就相当于用ryan得权限执行了cmd
从这里可以看出,如果系统中存在su;
即使是普通用户,只要将
if (myuid != AID_ROOT && myuid != AID_SHELL) {
fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
return 1;
}
这一段代码注释。那么就可以拿着su 执行系统中的程序。
文件位置: $android/system/extras/su/
Android.mk:
<span style="font-size:12px;">LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= su.c LOCAL_MODULE:= su LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_STATIC_LIBRARIES := libc LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE)</span>
LOCAL_MODULE_TAGS 为debug 表示,只有debug版本才编译;
如果希望在其他,参看:http://blog.csdn.net/passerbysrs/article/details/46650113
再看源码:
<span style="font-size:12px;">/* ** ** Copyright 2008, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #define LOG_TAG "su" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <dirent.h> #include <errno.h> #include <unistd.h> #include <time.h> #include <pwd.h> #include <private/android_filesystem_config.h> /* * SU can be given a specific command to exec. UID _must_ be * specified for this (ie argc => 3). * * Usage: * su 1000 * su 1000 ls -l */ int main(int argc, char **argv) { struct passwd *pw; int uid, gid, myuid; /* Until we have something better, only root and the shell can use su. */ myuid = getuid(); if (myuid != AID_ROOT && myuid != AID_SHELL) { fprintf(stderr,"su: uid %d not allowed to su\n", myuid); return 1; } if(argc < 2) { uid = gid = 0; } else { pw = getpwnam(argv[1]); if(pw == 0) { uid = gid = atoi(argv[1]); } else { uid = pw->pw_uid; gid = pw->pw_gid; } } if(setgid(gid) || setuid(uid)) { fprintf(stderr,"su: permission denied\n"); return 1; } /* User specified command for exec. */ if (argc == 3 ) { if (execlp(argv[2], argv[2], NULL) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } else if (argc > 3) { /* Copy the rest of the args from main. */ char *exec_args[argc - 1]; memset(exec_args, 0, sizeof(exec_args)); memcpy(exec_args, &argv[2], sizeof(exec_args)); if (execvp(argv[2], exec_args) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } /* Default exec shell. */ execlp("/system/bin/sh", "sh", NULL); fprintf(stderr, "su: exec failed\n"); return 1; } </span>
来看看uid的定义:
system/core/include/private/android_filesystem_config.h:
<span style="font-size:12px;">#define AID_ROOT 0 /* traditional unix root user */</span>
<span style="font-size:12px;">#define AID_SHELL 2000 /* adb and debug shell user */ </span>
一些预备知识:
getpwnam() 用于获取用户登录相关信息
getuid()用来取得执行目前进程的用户识别码
execlp
int execlp(const char * file,const char * arg,...,(char *)0);
execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。
setgid和setuid :
参看http://blog.chinaunix.net/uid-793704-id-2545508.html
http://blog.csdn.net/passerbysrs/article/details/46650731
目的:setuid 和setgid是让普通用户可以以root用户的角色运行只有root帐号才能运行的程序或命令。
内核检查一个进程是否具有访问某权限时,是使用进程的有效用户 ID 来进行检查的;
UID和GID这样的标识符会影响文件的所有权和访问许可,以及向其它进程发送信号的能力。这些属性统称为凭证。
每个进程都有两对ID ——真实的和有效的。当一个用户登录的时候,login程序会把两对ID设置成密码数据库(/etc/passwd文件,或某些如Sun Microsystems的NIS之类的分布式机制)中指定的UID和GID。当一个进程fork的时候,子进程将从父进程那儿继承它的凭证。
有效UID和有效GID印象文件的创建和访问。在创建文件的时候,内核将文件的所有者属性设置成创建进程的有效UID和有效GID。在访问文件的时候,内核使用进程的有效UID和GID来判断它是否能够访问该文件。真实UID和真实GID标识进程的真实所有者,会影响到发送信号的权限。对于一个没有超级用户权限的进程来说,仅当它的真实或有效UID于另一个进程的真实UID匹配时它才能向那个进程发送信号。
setuid系统调用的语法是 setuid(uid) ,其中,uid是新的用户ID,该系统调用的结果取决于有效用户ID的当前值。
如果调用进程的有效用户ID是超级用户,内核会把进程表以及u区中的真实和有效用户ID都设置成uid。
如果调用进程的有效用户ID不是超级用户,仅当uid等于真实用户ID或保存用户ID时,内核才会把u区中的有效用户ID设置成uid。
否则,该系统调用将返回错误。
一般来说,一个进程会在fork系统调用期间从父进程那儿继承它的真实和有效用户ID,这些数值即使经过exec系统调用也会保持不变。
在 root 下,实际用户 ID 和有效用户 ID 均能被设为 setuid() 修改。
比如我们用普通用户运行passwd命令来更改自己的口令,实际上最终更改的是/etc/passwd文件。
我们知道/etc/passwd文件是用户管理的配置文件,只有root权限的用户才能更改。
<span style="font-size:12px;">[root@localhost ~]# ls -l /etc/passwd -rw-r--r-- 1 root root 2379 04-21 13:18 /etc/passwd</span>
作为普通用户如果修改自己的口令通过修改/etc/passwd肯定是不可完成的任务,但是不是可以通过一个命令来修改呢。答案是肯定的,作为普通用户可以通过passwd 来修改自己的口令。这归功于passwd命令的权限。我们来看一下;
<span style="font-size:12px;">[root@localhost ~]# ls -l /usr/bin/passwd -r-s--x--x 1 root root 21944 02-12 16:15 /usr/bin/passwd</span>
因为/usr/bin/passwd 文件已经设置了setuid 权限位(也就是r-s--x--x中的s),所以普通用户能临时变成root,间接的修改/etc/passwd,以达到修改自己口令的权限。
setuid和setgid的实例应用;
我们想让一个普通用户beinan拥有root用户拥有超级rm删除权限,我们除了用su或sudo 临时切换到 root身份操作以外,还能怎么做呢???
<span style="font-size:12px;">[root@localhost ~]#cd /home 注:进入/home目录 [root@localhost home]# touch beinantest.txt 注:创建一个测试文件;</span>
<span style="font-size:12px;">[root@localhost home]# ls -l beinantest.txt 注:查看文件属性; -rw-r--r-- 1 root root 0 04-24 18:03 beinantest.txt 注:文件的属性;</span>
<span style="font-size:12px;">[root@localhost home]# su beinan 注:切换到普通用户 beinan [beinan@localhost home]$ rm -rf beinantest.txt 注:以普通用户身份来删除beinantest.txt文件; </span>
rm: 无法删除 “beinantest.txt”: 权限不够
那我们怎么才能让beinan 这个普通用户也拥有root超级的rm 删除功力呢?
<span style="font-size:12px;">[root@localhost ~]# ls -l /bin/rm -rwxr-xr-x 1 root root 93876 02-11 14:43 /bin/rm </span>
<span style="font-size:12px;">[root@localhost ~]# chmod 4755 /bin/rm 注:设置rm的权限为4755 , 就把setuid 位设置好了。 [root@localhost ~]# ls -l /bin/rm -rwsr-xr-x 1 root root 43980 02-11 14:43 /bin/rm [root@localhost ~]# cd /home/ [root@localhost home]# su beinan 注:切换到beinan用户身份; [root@localhost home]$ ls -l beinantest.txt 注:查看文件属性; -rw-r--r-- 1 root root 0 04-24 18:03 beinantest.txt 注:文件的属性;</span>
<span style="font-size:12px;">[beinan@localhost home]$ rm -rf beinantest.txt 注:删除beinantest.txt文件;</span>
我们只是设置了rm的setuid位,让普通用户在rm指令上有超级root的删除超级权力。
通过这个例子,我们应该能明白setuid和setgid位的应用了,如同前面所说,让普通用户超越本身的能力,让普通用户能执行只有root才能执行的命令。在这一点,我们要和su和sudo 区分开来。请参见su和sudo的文档:《Linux 系统中的超级权限的控制》
开始分析:
a. 执行用户权限识别
getuid() 之后判定当前执行用户的uid是否是root 或者debug shell user
b. 判定参数
如果 argc < 2 : 表示只执行了su ; 那么就将uid和gid都设为0,即Root账户的uid与gid
否则的话: 比如su ryan , 则通过getpwnam() 获取ryan的相关信息,并将ryan的uid和gid取出来保存;
c. setgid 和setuid
假设当前进入系统后的用户是alex, 在./下有个cmd 二进制,它的创建有拥有者是ryan;
alex是没有权限执行的;
因此必须用如下方法
比如system/xbin/su ryan cmd others
argc[0]: su
argc[1]: ryan
argc[2]: cmd
argc[3]: others
先看看init.rc的权限:
setuid = chmod u+s xxx # 设置setuid权限
setgid = chmod
g+s xxx # 设置setgid权限
首先获取ryan的 uid和gid
然后通过setuid和setgid将ryan的uid和gid设置到进程中;
这个时候就相当于用ryan得权限执行了cmd
从这里可以看出,如果系统中存在su;
即使是普通用户,只要将
if (myuid != AID_ROOT && myuid != AID_SHELL) {
fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
return 1;
}
这一段代码注释。那么就可以拿着su 执行系统中的程序。
相关文章推荐
- Android内部存储与外置SDCard
- 查看安卓应用包名
- Android程序:程序中的文件读写实例
- 定制Android ListView 快速滚动的滚动条-fast scroll bar thumb
- [置顶] Android开发中正确删除Log的姿势(proguard.config=proguard.cfg)
- Android Animation
- android MD5校验码的生成与算法实现
- Android 存储相关的名词解释
- 解决Android中Handler警告、SimpleDateFormat警告、"String".toUpperCase()警告
- 解决Android中Handler警告、SimpleDateFormat警告、"String".toUpperCase()警告
- 解决Android中Handler警告、SimpleDateFormat警告、"String".toUpperCase()警告
- 解决Android中Handler警告、SimpleDateFormat警告、"String".toUpperCase()警告
- 解决Android中Handler警告、SimpleDateFormat警告、"String".toUpperCase()警告
- android ndk
- Android Matrix理论与应用详解
- Chrome on Android的开发调试技术
- Android 触摸事件传递机制
- 使用自定义的BaseAdapter实现 onitemclickListener
- android:focusable和android:focusableInTouchMode的区别
- Android 注解和反射原理和实现学习(下)