android su源码

2024-08-20 20:58
文章标签 android 源码 su

本文主要是介绍android su源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

android su 通过源码编译出来的;

文件位置: $android/system/extras/su/

Android.mk: 


<span style="font-size:12px;">LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_SRC_FILES:= su.cLOCAL_MODULE:= suLOCAL_FORCE_STATIC_EXECUTABLE := trueLOCAL_STATIC_LIBRARIES := libcLOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := debuginclude $(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 su源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1091153

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk