抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

这里没什么,做一个记录

0x0 入手点

可以看到有设置选项,尝试切换(以firefox nightly 为例, package name = org.mozilla.fenix):

1
2
3
4
SP.AccelerationUtils    com.oplus.securitypermission         I  addUserSetPackage success: package=org.mozilla.fenix, userId=0  // 我以前没设置过
SP.AccelerationSettingsManger com.oplus.securitypermission I set state: uid=10352, pkg=org.mozilla.fenix, userId=0, state=0 // 允许
SP.AccelerationSettingsManger com.oplus.securitypermission I set state: uid=10352, pkg=org.mozilla.fenix, userId=0, state=3 // 6s
SP.AccelerationSettingsManger com.oplus.securitypermission I set state: uid=10352, pkg=org.mozilla.fenix, userId=0, state=1 // 不允许

可以看到,这个是由 com.oplus.securitypermission 发出的log,那么这个包是什么呢

1
2
❯ adb -d shell pm path com.oplus.securitypermission
package:/system_ext/app/SecurityPermission/SecurityPermission.apk

顺着我们就能找到 APK,正好一加 ROOT 方便,这边直接拿走文件进行解析

1
2
3
❯ adb -d pull /system_ext/app/SecurityPermission/SecurityPermission.apk
❯ md5sum SecurityPermission.apk
1ed3009e6f49d50801b8b4ab44ecdfe2 SecurityPermission.apk

0x1 SecurityPermission.apk

还记得上面 Log 的 TAG AccelerationSettingsManger 吗,总所周知, TAG 这东西一般都是写死的字符串常量,我们直接在 JADX 里面进行搜索

诶,这不就找到了,下面是代码选取的部分

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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package aa;

import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.UserHandle;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

/* compiled from: AccelerationSettingsManger.java */
/* loaded from: classes2.dex */
public class f implements AppOpsManager.OnOpChangedListener {

/* renamed from: g, reason: collision with root package name */
private static final f f193g = new f();

/* renamed from: a, reason: collision with root package name */
private boolean f194a;

/* renamed from: c, reason: collision with root package name */
private Context f196c;

/* renamed from: e, reason: collision with root package name */
private AppOpsManager f198e;

/* renamed from: b, reason: collision with root package name */
private final ConcurrentHashMap<String, Integer> f195b = new ConcurrentHashMap<>();

/* renamed from: d, reason: collision with root package name */
private ArrayList<PackageManager.OnPermissionsChangedListener> f197d = new ArrayList<>();

/* renamed from: f, reason: collision with root package name */
private final BroadcastReceiver f199f = new a();

/* compiled from: AccelerationSettingsManger.java */
/* loaded from: classes2.dex */
class a extends BroadcastReceiver {
a() {
}

@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Uri data = intent.getData();
if (data == null) {
return;
}
String schemeSpecificPart = data.getSchemeSpecificPart();
if ("android.intent.action.PACKAGE_REMOVED".equals(action) && !intent.getBooleanExtra("android.intent.extra.REPLACING", false)) {
f.this.f195b.remove(schemeSpecificPart);
}
}
}

private f() {
}

public static f c() {
return f193g;
}

private int f(String str) {
try {
return this.f196c.getPackageManager().getPackageUidAsUser(str, UserHandle.myUserId());
} catch (PackageManager.NameNotFoundException e10) {
y7.a.f("AccelerationSettingsManger", "getUid NameNotFoundException = " + e10.getMessage());
return -1;
}
}

private synchronized void i(int i10) {
Iterator<PackageManager.OnPermissionsChangedListener> it = this.f197d.iterator();
while (it.hasNext()) {
it.next().onPermissionsChanged(i10);
}
}

public synchronized void b(PackageManager.OnPermissionsChangedListener onPermissionsChangedListener) {
if (!this.f197d.contains(onPermissionsChangedListener)) {
this.f197d.add(onPermissionsChangedListener);
}
}

public void d(Context context) {
ApplicationInfo applicationInfo;
this.f195b.clear();
for (PackageInfo packageInfo : context.getPackageManager().getInstalledPackagesAsUser(0, context.getUserId())) {
if (packageInfo != null && (applicationInfo = packageInfo.applicationInfo) != null) {
int i10 = applicationInfo.uid;
boolean isSystemApp = applicationInfo.isSystemApp();
if (i10 >= 10000 && !isSystemApp) {
String str = packageInfo.packageName;
this.f195b.put(str, Integer.valueOf(this.f198e.unsafeCheckOpRawNoThrow(10002, i10, str)));
}
}
}
}

public int e(String str) {
if (f(str) < 0) {
return 3;
}
Integer num = this.f195b.get(str);
if (num == null) {
num = Integer.valueOf(this.f198e.unsafeCheckOpRawNoThrow(10002, f(str), str));
this.f195b.put(str, num);
}
return num.intValue();
}

public void g(Context context) {
this.f196c = context;
boolean C = n.C(context);
this.f194a = C;
if (C) {
this.f198e = (AppOpsManager) context.getSystemService("appops");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.PACKAGE_REMOVED");
intentFilter.addDataScheme("package");
this.f196c.registerReceiver(this.f199f, intentFilter, 2);
d(context);
this.f198e.startWatchingMode(10002, (String) null, this);
}
}

public boolean h() {
return this.f194a;
}

public void j(String str) {
try {
ApplicationInfo applicationInfo = this.f196c.getPackageManager().getPackageInfo(str, 0).applicationInfo;
if (applicationInfo != null) {
i(applicationInfo.uid);
}
} catch (PackageManager.NameNotFoundException e10) {
y7.a.f("AccelerationSettingsManger", "notifyPermissionsChanged NameNotFoundException = " + e10.getMessage());
}
}

public synchronized void k(PackageManager.OnPermissionsChangedListener onPermissionsChangedListener) {
this.f197d.remove(onPermissionsChangedListener);
}

public void l(String str, int i10) {
m(str, i10, true, true);
}

public void m(String str, int i10, boolean z10, boolean z11) {
if (!TextUtils.isEmpty(str) && f(str) >= 0) {
if (z11) {
j(str);
}
Integer num = this.f195b.get(str);
if (num == null || num.intValue() != i10) {
this.f195b.put(str, Integer.valueOf(i10));
if (z10) {
this.f198e.setUidMode(10002, f(str), i10);
this.f198e.setMode(10002, f(str), str, i10);
n.h(this.f196c, str);
y7.a.h("AccelerationSettingsManger", "set state: uid=" + f(str) + ", pkg=" + str + ", userId=" + UserHandle.myUserId() + ", state=" + i10);
}
}
}
}

@Override // android.app.AppOpsManager.OnOpChangedListener
public void onOpChanged(String str, String str2) {
int f10 = f(str2);
if (f10 < 0) {
return;
}
int unsafeCheckOpRawNoThrow = this.f198e.unsafeCheckOpRawNoThrow(10002, f10, str2);
if (unsafeCheckOpRawNoThrow != e(str2)) {
m(str2, unsafeCheckOpRawNoThrow, false, true);
}
y7.a.d("AccelerationSettingsManger", "onOpChanged: pkg=" + str2 + ", uid=" + f10 + ", userId=" + UserHandle.myUserId());
}
}

我们不用管看不看得懂,直接看到有 log 的那句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void m(String str, int i10, boolean z10, boolean z11) {
if (!TextUtils.isEmpty(str) && f(str) >= 0) {
if (z11) {
j(str);
}
Integer num = this.f195b.get(str);
if (num == null || num.intValue() != i10) {
this.f195b.put(str, Integer.valueOf(i10));
if (z10) {
this.f198e.setUidMode(10002, f(str), i10);
this.f198e.setMode(10002, f(str), str, i10);
n.h(this.f196c, str);
y7.a.h("AccelerationSettingsManger", "set state: uid=" + f(str) + ", pkg=" + str + ", userId=" + UserHandle.myUserId() + ", state=" + i10);
}
}
}
}

看到

1
2
3
private AppOpsManager f198e;
...
this.f198e.setMode(10002, f(str), str, i10);

如果你对设置权限这些的熟悉,其实能看出来这就是这里

1
2
3
4
5
6
7
8
9
10
11
/** @hide */
@UnsupportedAppUsage
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

那可以去查询吗,很可惜不行,因为唯一一个能用 int op 查询的方法 public int checkOpNoThrow(int op, int uid, String packageName)

1
2
Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;)I,unsupported
Landroid/app/AppOpsManager;->checkOpNoThrow(IILjava/lang/String;Ljava/lang/String;I)I,blocked

而我们的目标是 Android 15,那有什么办法可以避免调用 hidden api 呢

当然有,public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) 就为我们准备了 API,现在的问题是, op 的 String 要从哪里来

0x2 framework.jar

既然这里用了 ApplicationInfo,那么 framework.jar 里面肯定有它的实现,这个类一定就认识这个 op,那看看这个类怎么实现的

先对 10002 进行搜索,虽然没搜到,但是找到了

1
2
3
4
5
6
public static String opToPermission(int op) {
if (op > 10000) {
return APP_OPS_MANAGER_EXT.getCustomOpToPermission(op);
}
return sAppOpInfos[op].permission;
}

这个 EXT 又是什么呢

1
private static final IAppOpsManagerExt APP_OPS_MANAGER_EXT = (IAppOpsManagerExt) ExtLoader.type(IAppOpsManagerExt.class).create();

可以看到是一个 IAppOpsManagerExt,这个类里面又有什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IAppOpsManagerExt {
public static final int CUSTOM_NUM_OP = 10003;
public static final int OP_CUSTOM_NONE = 10000;
public static final int OP_DIRECTION_SENSORS = 10002;
public static final int OP_GET_INSTALLED_APPS = 10001;
public static final int[] sCustomOpToSwitch = {10001, 10002};
public static final String OPSTR_GET_INSTALLED_APPS = "android:get_installed_apps";
public static final String OPSTR_DIRECTION_SENSORS = "android:direction_sensors";
public static final String[] sCustomOpToString = {OPSTR_GET_INSTALLED_APPS, OPSTR_DIRECTION_SENSORS};
public static final String[] sCustomOpNames = {"GET_INSTALLED_APPS", "DIRECTION_SENSORS"};
public static final int[] sCustomRuntimeOps = {10001, 10002};
public static final String[] sCustomOpPerms = {"com.android.permission.GET_INSTALLED_APPS", null};
public static final String[] sCustomOpRestrictions = {null, null};
public static final AppOpsManager.RestrictionBypass[] sCustomOpAllowSystemRestrictionBypass = {null, null};
public static final int[] sCustomOpDefaultMode = {3, 3};
public static final boolean[] sCustomOpDisableReset = {false, false};
public static final HashMap<String, Integer> sCustomOpStrToOp = new HashMap<String, Integer>() { // from class: android.app.IAppOpsManagerExt.1
{
put(IAppOpsManagerExt.OPSTR_GET_INSTALLED_APPS, 10001);
put(IAppOpsManagerExt.OPSTR_DIRECTION_SENSORS, 10002);
}
};
}

看来已经找到了 String 的表示法 android:direction_sensors,从这里就可以去查询我们是否被设置了6s