- UID
- 2
- 精华
- 积分
- 7736
- 威望
- 点
- 宅币
- 个
- 贡献
- 次
- 宅之契约
- 份
- 最后登录
- 1970-1-1
- 在线时间
- 小时
|
这里介绍的是绝对可行的root方式,对于android模拟器,无论x86 x64 ,无论4.0 5.0 6.0都适用
真机的话5.0和6.0,root成功率比较低,因此不适合在上面做root方面的测试,这时只能考虑虚拟机,因为虚拟机adb有root权限,利用adb root权限便可以提升su权限
网上盛传的方法是http://androidsu.com/superuser https://www.0xaa55.com/forum.php ... tid=1648&extra=
需要superuser.apk,我分析了该网站的su,发现除了传统su的流程(setuid setgid)外,还加入了和superuser.apk通信的这一步
superuser.apk用于单个app权限设置。
遗憾的是该作者并没完成mips架构,和5.0以上的su适配
默认的su,是只允许root权限和shell权限来执行的,因此一般的app并不能使用,因此这也是我们修改的重点,同时还要给su加上必要的环境变量
我这种方式,去除了权限判断部分,因此减少了某些情况下由于这部分带来的root权限未成功获取的bug
这里提供一种方式,可以支持全平台
先构造文件夹:
/jni
/jni/su.cpp
/jni/Android.mk
/jni/Application.mk
- //su.cpp
- /*
- * Copyright (C) 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.
- */
- #include <errno.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <pwd.h>
- #define AID_ROOT 0 /* traditional unix root user */
- #define AID_SYSTEM 1000 /* system server */
- #define AID_SHELL 2000 /* adb and debug shell user */
- #define AID_NOBODY 9999
- #define AID_APP 10000 /* first app user */
- #define AID_USER 100000 /* offset for uid ranges for each user */
- void pwtoid(const char* tok, uid_t* uid, gid_t* gid) {
- struct passwd* pw = getpwnam(tok);
- if (pw)
- {
- if (uid) *uid = pw->pw_uid;
- if (gid) *gid = pw->pw_gid;
- }
- else
- {
- char* end;
- errno = 0;
- uid_t tmpid = strtoul(tok, &end, 10);
- if (errno != 0 || end == tok)
- printf("invalid uid/gid '%s'", tok);
- if (uid) *uid = tmpid;
- if (gid) *gid = tmpid;
- }
- }
- void extract_uidgids(const char* uidgids, uid_t* uid, gid_t* gid, gid_t* gids, int* gids_count) {
- char *clobberablegids;
- char *nexttok;
- char *tok;
- int gids_found;
- if (!uidgids || !*uidgids)
- {
- *gid = *uid = 0;
- *gids_count = 0;
- return;
- }
- clobberablegids = strdup(uidgids);
- strcpy(clobberablegids, uidgids);
- nexttok = clobberablegids;
- tok = strsep(&nexttok, ",");
- pwtoid(tok, uid, gid);
- tok = strsep(&nexttok, ",");
- if (!tok)
- {
- /* gid is already set above */
- *gids_count = 0;
- free(clobberablegids);
- return;
- }
- pwtoid(tok, NULL, gid);
- gids_found = 0;
- while ((gids_found < *gids_count) && (tok = strsep(&nexttok, ",")))
- {
- pwtoid(tok, NULL, gids);
- gids_found++;
- gids++;
- }
- if (nexttok && gids_found == *gids_count)
- {
- fprintf(stderr, "too many group ids\n");
- }
- *gids_count = gids_found;
- free(clobberablegids);
- }
- int main(int argc, char** argv)
- {
- uid_t current_uid = getuid();
- // Handle -h and --help.
- ++argv;
- if (*argv && (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0))
- {
- fprintf(stderr,
- "usage: su [UID[,GID[,GID2]...]] [COMMAND [ARG...]]\n"
- "\n"
- "Switch to WHO (default 'root') and run the given command (default sh).\n"
- "\n"
- "where WHO is a comma-separated list of user, group,\n"
- "and supplementary groups in that order.\n"
- "\n");
- return 0;
- }
- uid_t uid = 0;
- gid_t gid = 0;
- if (*argv)
- {
- gid_t gids[10];
- int gids_count = sizeof(gids)/sizeof(gids[0]);
- extract_uidgids(*argv, &uid, &gid, gids, &gids_count);
- if (gids_count) {
- if (setgroups(gids_count, gids))
- {
- printf("setgroups failed");
- }
- }
- ++argv;
- }
- if (setgid(gid))
- printf("setgid failed");
- if (setuid(uid))
- printf("setuid failed");
- //设置环境变量
- setenv("PATH", "/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin", 1);
- setenv("LD_LIBRARY_PATH", "/vendor/lib:/system/lib", 1);
- setenv("ANDROID_BOOTLOGO", "1", 1);
- setenv("ANDROID_ROOT", "/system", 1);
- setenv("ANDROID_DATA", "/data", 1);
- setenv("ANDROID_ASSETS", "/system/app", 1);
- setenv("EXTERNAL_STORAGE", "/sdcard", 1);
- setenv("ASEC_MOUNTPOINT", "/mnt/asec", 1);
- setenv("LOOP_MOUNTPOINT", "/mnt/obb", 1);
- char* exec_args[argc + 1];
- size_t i = 0;
- for (; *argv != NULL; ++i)
- {
- exec_args[i] = *argv++;
- }
- if (i == 0) exec_args[i++] = "/system/bin/sh";
- exec_args[i] = NULL;
- execvp(exec_args[0], exec_args);
- printf("failed to exec %s", exec_args[0]);
- }
- //Android.mk
- LOCAL_SRC_FILES := su.cpp
- LOCAL_MODULE := su
- LOCAL_MODULE_FILENAME := su
- LOCAL_LDFLAGS += -fPIE -pie
- LOCAL_CFLAGS += -fPIE
- include $(BUILD_EXECUTABLE)
- //Application.mk 根据自己的需求调整
- APP_ABI := armeabi
- APP_PLATFORM := android-15
复制代码
在jni目录下执行ndk-build即可,生成的su文件替换成/system/bin/mysu
模拟器中:
adb remount //使/system可写
adb push \??su /system/bin/mysu
adb shell chmod 6777 /system/bin/mysu //使普通进程可以执行su并获取root权限
我们用简单的代码测试:
- public static boolean canRunRootCommands() {
- boolean retval = false;
- Process suProcess;
- try {
- suProcess = Runtime.getRuntime().exec("mysu");
- DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
- DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
- if (null != os && null != osRes) {
- // Getting the id of the current user to check if this is root
- os.writeBytes("id\n");
- os.flush();
- String currUid = osRes.readLine();
- boolean exitSu = false;
- if (null == currUid) {
- retval = false;
- exitSu = false;
- Log.d("ROOT", "Can't get root access or denied by user");
- } else if (true == currUid.contains("uid=0")) {
- retval = true;
- exitSu = true;
- Log.d("ROOT", "Root access granted");
- } else {
- retval = false;
- exitSu = true;
- Log.d("ROOT", "Root access rejected: " + currUid);
- }
- if (exitSu) {
- os.writeBytes("exit\n");
- os.flush();
- }
- }
- } catch (Exception e) {
- // Can't get root !
- // Probably broken pipe exception on trying to write to output
- // stream after su failed, meaning that the device is not rooted
- retval = false;
- Log.d("ROOT",
- "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
- }
- return retval;
- }
复制代码
可以发现是成功的 |
|