root android模拟器的最通用方式
这里介绍的是绝对可行的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?mod=viewthread&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 ...]] ]\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;
int gids_count = sizeof(gids)/sizeof(gids);
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;
size_t i = 0;
for (; *argv != NULL; ++i)
{
exec_args = *argv++;
}
if (i == 0) exec_args = "/system/bin/sh";
exec_args = NULL;
execvp(exec_args, exec_args);
printf("failed to exec %s", exec_args);
}
//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;
}
可以发现是成功的
页:
[1]