首页
社区
课程
招聘
编译aosp 13在非root环境下给指定app设置root权限
发表于: 2024-11-9 22:32 2425

编译aosp 13在非root环境下给指定app设置root权限

2024-11-9 22:32
2425

在做设备指纹分析时,需要从一个干净的设备中提取出设备指纹的json做差异分析,综合评估打算编译aosp来实现。
想到操作内存读写是需要有root权限的,首先要对目标app的pid和gid做修改。
首先我们要对Zygote有亿点点了解,chatgpt的理解如下

1
Zygote是Android系统中的一个进程,它负责启动系统的初始化以及其他应用进程的启动。在Android系统中,Zygote进程通过调用ZygoteInit.zygoteMain方法来完成自身的初始化工作,并且通过调用ZygoteInit.childMain方法来启动新的应用进程。

查看childMain代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/**
 * Specialize the current process into one described by argBuffer or the command read from
 * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close
 * it. Used both for a specializing a USAP process, and for process creation without USAPs.
 * In both cases, we specialize the process after first returning to Java code.
 *
 * @param writePipe  The write end of the reporting pipe used to communicate with the poll loop
 *                   of the ZygoteServer.
 * @return A runnable oject representing the new application.
 */
private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer,
                                  @Nullable LocalServerSocket usapPoolSocket,
                                  FileDescriptor writePipe) {
    final int pid = Process.myPid();
 
    DataOutputStream usapOutputStream = null;
    ZygoteArguments args = null;
 
    LocalSocket sessionSocket = null;
    if (argBuffer == null) {
        // Read arguments from usapPoolSocket instead.
 
        Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
 
        // Change the priority to max before calling accept so we can respond to new
        // specialization requests as quickly as possible.  This will be reverted to the
        // default priority in the native specialization code.
        boostUsapPriority();
 
        while (true) {
            ZygoteCommandBuffer tmpArgBuffer = null;
            try {
                sessionSocket = usapPoolSocket.accept();
                // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
                // This is safe from a race condition because the pool is only flushed after
                // the SystemServer changes its internal state to stop using the USAP pool.
                blockSigTerm();
 
                usapOutputStream =
                        new DataOutputStream(sessionSocket.getOutputStream());
                Credentials peerCredentials = sessionSocket.getPeerCredentials();
                tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
                args = ZygoteArguments.getInstance(tmpArgBuffer);
                applyUidSecurityPolicy(args, peerCredentials);
                // TODO (chriswailes): Should this only be run for debug builds?
                validateUsapCommand(args);
                break;
            } catch (Exception ex) {
                Log.e("USAP", ex.getMessage());
            }
            // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
            unblockSigTerm();
            IoUtils.closeQuietly(sessionSocket);
            IoUtils.closeQuietly(tmpArgBuffer);
        }
    } else {
        // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
        blockSigTerm();
        try {
            args = ZygoteArguments.getInstance(argBuffer);
        } catch (Exception ex) {
            Log.e("AppStartup", ex.getMessage());
            throw new AssertionError("Failed to parse application start command", ex);
        }
        // peerCredentials were checked in parent.
    }
    if (args == null) {
        throw new AssertionError("Empty command line");
    }
    try {
        // SIGTERM is blocked here.  This prevents a USAP that is specializing from being
        // killed during a pool flush.
 
        applyDebuggerSystemProperty(args);
 
        int[][] rlimits = null;
 
        if (args.mRLimits != null) {
            rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
        }
 
        if (argBuffer == null) {
            // This must happen before the SELinux policy for this process is
            // changed when specializing.
            try {
                // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
                // Process.ProcessStartResult object.
                usapOutputStream.writeInt(pid);
            } catch (IOException ioEx) {
                Log.e("USAP", "Failed to write response to session socket: "
                        + ioEx.getMessage());
                throw new RuntimeException(ioEx);
            } finally {
                try {
                    // Since the raw FD is created by init and then loaded from an environment
                    // variable (as opposed to being created by the LocalSocketImpl itself),
                    // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See
                    // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd).
                    // Thus closing the LocalSocket does not suffice. See b/130309968 for more
                    // discussion.
                    FileDescriptor fd = usapPoolSocket.getFileDescriptor();
                    usapPoolSocket.close();
                    Os.close(fd);
                } catch (ErrnoException | IOException ex) {
                    Log.e("USAP", "Failed to close USAP pool socket");
                    throw new RuntimeException(ex);
                }
            }
        }
 
        if (writePipe != null) {
            try {
                ByteArrayOutputStream buffer =
                        new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
                DataOutputStream outputStream = new DataOutputStream(buffer);
 
                // This is written as a long so that the USAP reporting pipe and USAP pool
                // event FD handlers in ZygoteServer.runSelectLoop can be unified.  These two
                // cases should both send/receive 8 bytes.
                // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects
                // a different format.
                outputStream.writeLong(pid);
                outputStream.flush();
                Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
            } catch (Exception ex) {
                Log.e("USAP",
                        String.format("Failed to write PID (%d) to pipe (%d): %s",
                                pid, writePipe.getInt$(), ex.getMessage()));
                throw new RuntimeException(ex);
            } finally {
                IoUtils.closeQuietly(writePipe);
            }
        }
 
        specializeAppProcess(args.mUid, args.mGid, args.mGids,
                             args.mRuntimeFlags, rlimits, args.mMountExternal,
                             args.mSeInfo, args.mNiceName, args.mStartChildZygote,
                             args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
                             args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
                             args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
 
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
        return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
                                     args.mDisabledCompatChanges,
                                     args.mRemainingArgs,
                                     null /* classLoader */);
    } finally {
        // Unblock SIGTERM to restore the process to default behavior.
        unblockSigTerm();
    }
}

其中调用了applyUidSecurityPolicy方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * Adjust uid and gid arguments, ensuring that the security policy is satisfied.
 * @param args non-null; zygote spawner arguments
 * @param peer non-null; peer credentials
 * @throws ZygoteSecurityException Indicates a security issue when applying the UID based
 *  security policies
 */
static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
        throws ZygoteSecurityException {
 
    if (args.mUidSpecified && (args.mUid < minChildUid(peer))) {
        throw new ZygoteSecurityException(
                "System UID may not launch process with UID < "
                + Process.SYSTEM_UID);
    }
 
    // If not otherwise specified, uid and gid are inherited from peer
    if (!args.mUidSpecified) {
        args.mUid = peer.getUid();
        args.mUidSpecified = true;
    }
    if (!args.mGidSpecified) {
        args.mGid = peer.getGid();
        args.mGidSpecified = true;
    }
}

applyUidSecurityPolicy方法的作用是调整 UID 和 GID 参数,确保满足安全策略。
所以我们先要了解uid的区间都代表什么再对此处做修改

1
2
3
4
5
6
7
8
9
10
11
12
0: root用户,可以访问和修改系统中的所有文件和目录,无论它们的权限设置如何。
1000:system 用户,许多核心系统服务运行在这个 UID 下。
1001:radio 用户,负责无线电和电话服务。
1002:bluetooth 用户,负责蓝牙服务。
1003:graphics 用户,负责图形服务。
1004input 用户,负责输入服务。
1005:audio 用户,负责音频服务。
1006:camera 用户,负责相机服务。
1007:log 用户,负责日志服务。
1008:compass 用户,负责指南针服务。
1009:mount 用户,负责挂载服务。
1010:wifi 用户,负责 Wi-Fi 服务。

由此可见我们在此处做下过滤即可将我们内存读写app设定UID为0,用户组GID也设定为0

GID:在 Android 中,GID(组标识符,Group ID)用于标识用户组,并控制组成员对系统资源的访问权限

1
2
3
4
5
6
if (args.mNiceName.equals("com.xxxxx") ||
            args.mNiceName.equals("com.xxxxx") ||
            args.mNiceName.equals("com.xxxxx")){
            args.mUid = 0;
            args.mGid = 0;
        }

测试后发现会报一个错

1
Package com.xxxx does not belong to

根据错误日志在aosp源代码中搜索到是
base/core/java/android/app/AppOpsManager.java的checkPackage报错,此处也直接过滤掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * @deprecated Use {@link PackageManager#getPackageUid} instead
 */
@Deprecated
public void checkPackage(int uid, @NonNull String packageName) {
    try {
        // fix Package com.xxxx does not belong to xxxx
        if (packageName.equals("com.xxxxx") ||
                packageName.equals("com.xxxxx") ||
                packageName.equals("com.xxxxx")){
            return;
        }
        if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
            throw new SecurityException(
                    "Package " + packageName + " does not belong to " + uid);
        }
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

亲测可用


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 4
支持
分享
最新回复 (4)
雪    币: 542
活跃值: (3004)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-11-10 19:31
0
雪    币: 247
活跃值: (260)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
SELinux过不去,有Root权限也是半残
6天前
0
雪    币: 863
活跃值: (1265)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
tmi
4
selinux过不去,只有名义上的root权限,建议修改selinux规则+内核
或者魔改各种root工具吧,简单通用点
6天前
0
雪    币: 1379
活跃值: (2796)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢分享
6天前
0
游客
登录 | 注册 方可回帖
返回
//