目录结构  ─ hello
  ├── jni
    ├── Android.mk

    └── hello.c

编译步骤:

# cd hello
# export NDK_PROJECT_PATH=`pwd`
# ndk-build
# adb push libs/armeabi/helloworld /data
# adb shell
# cd /data
# ls -l
# ./helloworld
Hello World!

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -pie -fPIE

LOCAL_LDFLAGS += -pie -fPIE

LOCAL_MODULE := sur

LOCAL_SRC_FILES := su.c

# LOCAL_STATIC_LIBRARIES := \

#     liblog \

#     libc \

LOCAL_LDLIBS := \

-llog \

-lc \

LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)

LOCAL_MODULE_TAGS := eng debug

LOCAL_FORCE_STATIC_EXECUTABLE := true

include $(BUILD_EXECUTABLE)

su.c  (删除权限检查部分)

/*
**
** 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; uid = ;
gid = ; /*
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;
}
} //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(setgid(gid) || setuid(uid)) {
fprintf(stderr,"su: permission denied\n");
return ;
} /* User specified command for exec. */
if (argc == ) {
if (execlp(argv[], argv[], NULL) < ) {
fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[],
strerror(errno));
return -errno;
}
} else if (argc > ) {
/* Copy the rest of the args from main. */
char *exec_args[argc - ];
memset(exec_args, , sizeof(exec_args));
memcpy(exec_args, &argv[], sizeof(exec_args));
if (execvp(argv[], exec_args) < ) {
fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[],
strerror(errno));
return -errno;
}
} /* Default exec shell. */
execlp("/system/bin/sh", "sh", NULL); fprintf(stderr, "su: exec failed\n");
return ;
}

代码中使用su

Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("mount -oremount,rw " + "/system\n");
os.writeBytes("busybox cp " + zlsuPath + " /system/bin/" + Constants.ROOT_SU + "\n");
os.writeBytes("busybox chown 0:0 /system/bin/" + Constants.ROOT_SU + "\n");
os.writeBytes("chmod 4755 /system/bin/" + Constants.ROOT_SU + "\n");
os.writeBytes("exit\n");
os.flush();
直接使用chmod出错,很多版本的chmod不支持a+s
# chmod a+s su
Bad mode 使用busybox
# busybox chmod a+s su 查找挂载位置(mmcblk0p10-->system)
# df

  Filesystem Size Used Free Blksize
  /dev 1006.3M 40.0K 1006.3M 4096
  /sys/fs/cgroup 1006.3M 0.0K 1006.3M 4096
  /mnt/asec 1006.3M 0.0K 1006.3M 4096
  /mnt/obb 1006.3M 0.0K 1006.3M 4096
  /system 1.5G 421.6M 1.1G 4096
  /cache 122.0M 144.0K 121.8M 4096
  /metadata 11.7M 40.0K 11.7M 4096
  /data 991.9M 591.2M 400.7M 4096
  /mnt/usb_storage 1006.3M 0.0K 1006.3M 4096
  /mnt/internal_sd 11.7G 22.2M 11.7G 8192
  /mnt/secure/asec 11.7G 22.2M 11.7G 8192

# cat /proc/partitions

  major minor #blocks name

  254 0 520912 zram0
  179 0 15267840 mmcblk0
  179 1 4096 mmcblk0p1
  179 2 4096 mmcblk0p2
  179 3 16384 mmcblk0p3
  179 4 16384 mmcblk0p4
  179 5 32768 mmcblk0p5
  179 6 32768 mmcblk0p6
  179 7 53248 mmcblk0p7
  179 8 131072 mmcblk0p8
  179 9 4096 mmcblk0p9
  179 10 1572864 mmcblk0p10
  179 11 16384 mmcblk0p11
  179 12 4096 mmcblk0p12
  179 13 1048576 mmcblk0p13
  179 14 65536 mmcblk0p14
  179 15 12257280 mmcblk0p15

adb shell mount -o rw,remount /system
adb push su /system/xbin/su
adb shell chmod /system
adb shell chmod /system/xbin/su

最后已失败告终!!

Android目前的ROOT的基本原理,是通过系统漏洞获取ROOT SHELL权限,然后往手机里面push 最核心的两个文件,su可执行文件和superUSer.apk。 后者用于管理对应用的授权,而前者则真正用来提升权限至ROOT。 当APK需要进行高权限操作时,使用Shell方式进行: su xxxxx 即可,此时(假设用户授权了,通过superUser.apk)xxxx的命令就会以ROOT用户权限方式执行。之所以push到手机中的su可以提升权限,其核心原理是su是Set-UID-Root的。具体原理分析,可参见本博客的 关于ROOT原理的文档,说明的非常详细了。

但是,在Android4.3中,从如下的open Source Code :dalvik_system_Zygote.cpp-》forkAndSpecializeCommon:

extern int gMallocLeakZygoteChild;
gMallocLeakZygoteChild = ; /* keep caps across UID change, unless we're staying root */
if (uid != ) {
err = prctl(PR_SET_KEEPCAPS, , , , ); if (err < ) {
ALOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
dvmAbort();
}
} for (int i = ; prctl(PR_CAPBSET_READ, i, , , ) >= ; i++) {
err = prctl(PR_CAPBSET_DROP, i, , , );
if (err < ) {
if (errno == EINVAL) {
ALOGW("PR_CAPBSET_DROP %d failed: %s. "
"Please make sure your kernel is compiled with "
"file capabilities support enabled.",
i, strerror(errno));
} else {
ALOGE("PR_CAPBSET_DROP %d failed: %s.", i, strerror(errno));
dvmAbort();
}
}
}

注意红色斜体的代码,这是4.3新加入的。新加入的这些代码,会导致set-uid-root不再起作用,也就是,原先的ROOT方案中的su+superUser.apk的模式不再工作了!!黑客们需要重新考虑新的ROOT方案了!360,腾讯等等一系列使用了ROOT权限的应用需要等待新的ROOT方案然后基于新的ROOT方案来调整提升权限的方式了,SU不再起作用了。

这里简单说明一下原因,详细的请参见Linux的Capacity机制。

Android中每个APK的进程是Zygote Fork出来的,默认Fork出来的进程的Real UID和EUID都是继承自Zygote,也就是ROOT,然后,Zygote会对子进程做一些特殊处理,上面的红色斜体代码的作用是,在新Fork的APK进程中Drop掉所有的BoundSet Capacity,原本Zygote的BoundSet Capacity是全1,然后在APK的子进程中主动的Drop掉所有的这些Capacity,接着会再调用setUID/SetGID将APK进程的UID/GID从ROOT修改为App安装时分配的ID(权限退化)。

这样,你会看到,APK所在的进程的UID/GID退化成非ROOT了,原本还能通过su来提升权限。但是,4.3里面连所有的BoundsetCapacity也全部Drop掉了,里面包含的SETUID的capacity也Drop了,这样就导致,在APK所在的进程以及任意其子进程中,都无法修改UID了,即便通过set-UID-Root方式也无法修改了。

Android开发之《制作自己的su文件》的更多相关文章

  1. Android开发之《ffmpeg解码mjpeg视频流》

    MJPEG格式和码流分析,MJPEG格式的一些简介 FFmpeg解码USB摄像头MJPEG输出:http://blog.csdn.net/light_in_dark/article/details/5 ...

  2. android 开发对gif解码(适配android 4.2、4.3、4.4版本)

    android 开发对gif解码(适配android 4.2.4.3.4.4版本) 使用方法: public class ImageInputActivity extends Activity imp ...

  3. 在iOS平台使用ffmpeg解码h264视频流(转)

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...

  4. 在iOS平台使用ffmpeg解码h264视频流

    来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,f ...

  5. Android开发——通过wifi接收IPCamera视频流

    前面,我们已经了解了怎么在android app上打开关闭和扫描,搜索wifi,现在,我来写一下怎么通过连接wifi来使app获取到IPCamera摄像头的视频. 一.通过URL获取视频的地址 二.创 ...

  6. android 开发 解码gif图片,获取每帧bitmap

    环境:android 4.3  (注意对于android4.4版本解码出来不正确,除了第一帧正确外,其余的都是显示不同的地方)  通用版本见: android 开发对gif解码(适配android 4 ...

  7. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  8. FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  9. FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

    前言   ffmpeg播放rtsp网络流和摄像头流.   Demo   使用ffmpeg播放局域网rtsp1080p海康摄像头:延迟0.2s,存在马赛克     使用ffmpeg播放网络rtsp文件流 ...

  10. [原]如何在Android用FFmpeg解码图像

    前一篇[原]如何用Android NDK编译FFmpeg 我们知道了如何使用NDK来编译Android平台下使用的FFmpeg动态库.这篇文章我们就可以使用Android下的JNI来调用FFMpeg进 ...

随机推荐

  1. JavaScript学习总结(一)

    概述 前端三剑客,html.css.js. 这三种语言基本是前端开发必备的东西,那么你知道这三种语言分别负责的功能是什么吗? html:负责了一个页面的结构 css:负责页面的样式 JavaScrip ...

  2. 信号分析——从傅里叶变化到FFT

    我们眼中的世界就像皮影戏的大幕布,幕布的后面有无数的齿轮,大齿轮带动小齿轮,小齿轮再带动更小的. 在最外面的小齿轮上有一个小人——那就是我们自己. 我们只看到这个小人毫无规律的在幕布前表演,却无法预测 ...

  3. CSS中的 position与Grid Layout

    [1]CSS之Position(定位布局): 现css常用的属性有5种: 1.static 2.absolute 3.fixed 4.relative 5.sticky. 1.static 表示元素的 ...

  4. Centos8无法安装screen的解决方法:使用epel安装screen

    选择了一个基础款的vps安装的镜像选了熟悉的centos的最新版centos8,但是在安装screen的时候,却安装不了,提示: No match for argument: screen 本来以为是 ...

  5. SQL触发器笔记

    触发器(Trigger)是在对表进行插入.更新.删除等操作时自动执行的存储过程. 触发器是一种特殊的存储过程,它在执行语言事件时自动生效,采用事件驱动机制.当某个触发事件发生时,定义在触发器中的功能将 ...

  6. 对于urllib.request模块

    Python 3.X版本后的urllib和urllib2 1---- 现在的Python已经出到了3.5.2 在Python 3以后的版本中,urllib2这个模块已经不单独存在(也就是说当你impo ...

  7. 吴裕雄--天生自然 pythonTensorFlow图形数据处理:将MNIST手写图片数据写入TFRecord文件

    import numpy as np import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_dat ...

  8. C++ malloc函数

    malloc的全称是memory allocation,中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内 ...

  9. 二十七、rsync同步工具

    1.什么是rsync? Rsync是一款开源的.快速的,多功能的,可实现全量及增量的本地或者远程数据同步备份的优秀工具.windows和linux都可以. 官网:http:www.samba.org/ ...

  10. 基础篇五:Nginx的目录和基础配置

    Yum安装目录:yum的方式安装 rpm -ql nginx 下面开始安装目录详解