MIUI隐私行为逆向分析
一直好奇,MIUI的隐私行为咋做的,但是一直没有什么动力去分析。目前公司有个新的活,做出来一套无侵入式的隐私分析沙箱,一开始认为单纯的填写相应API代码就行了,后来实操下来发现真的太天真了,那个UID调用的API无从知晓,而且无法控制UID
前言
一直好奇,MIUI的隐私行为咋做的,但是一直没有什么动力去分析。目前公司有个新的活,做出来一套无侵入式的隐私分析沙箱,一开始认为单纯的填写相应API代码就行了,后来实操下来发现真的太天真了,那个UID调用的API无从知晓,而且无法控制UID,所以突然想看看MIUI的隐私行为咋做的,才有这篇小文章。
过程
一开始肯定要定位那个App具体实现了隐私行为功能了,所以直接用adb的命令直接获取到隐私行为界面是在那个App下,然后从手机中提取出apk,再对apk内容进行分析。
adb shell dumpsys window | Select-String mCurrentFocus
mCurrentFocus=Window{d559062 mode=0 rootTaskId=378 u0 com.miui.securitycenter/com.miui.permcenter.settings.PrivacySettingsActivity}
com.miui.securitycenter/com.miui.permcenter.settings.PrivacySettingsActivity这也就是隐私行为的主界面了,所以直接提取出安全中心apk即可。
简单分析了下,
com.miui.permcenter.privacymanager.k.a 单个行为的具体细节
com.miui.permcenter.privacymanager.behaviorrecord.b.b.a App行为时间线
其中包含了应用图标、应用名称、应用行为名称、行为发生的时间、行为时间线(MIUI自己的时间线UI功能,不多做赘述)。
com.miui.permcenter.privacymanager.k.a是主要的行为内容部分,所以掌握这块内容从哪里传过来的就很好办了。
com.miui.permcenter.privacymanager.k.a v0 = (com.miui.permcenter.privacymanager.k.a)this.b.get(arg9); // 设置行为信息
com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity // App behavior的界面
其中调用com.miui.permcenter.privacymanager.k.a 的为 this.f.add(new a());
com.miui.permcenter.privacymanager.behaviorrecord.c.a // 调用com.miui.permcenter.privacymanager.k.a 并进行初始化
静态分析看了半天,直接用frida trace下吧
*** exiting com.miui.permcenter.privacymanager.k.a.a
========================================================================================================================================================================================================Inspecting Fields: => true => class com.miui.permcenter.privacymanager.k.a
java.lang.String a => undefined => undefined
java.lang.String b => undefined => undefined
java.lang.String c => undefined => undefined
long d => undefined => undefined
int e => undefined => undefined
int f => undefined => undefined
java.lang.String g => undefined => undefined
java.lang.String h => undefined => undefined
int i => undefined => undefined
int j => undefined => undefined
int k => undefined => undefined
java.lang.CharSequence l => undefined => undefined
java.lang.CharSequence m => undefined => undefined
java.lang.String n => undefined => undefined
int o => undefined => undefined
java.lang.String p => null => null
int q => 0 => 0
com.miui.appmanager.i r => null => null
int s => 0 => 0
java.lang.String t => null => null
java.util.List u => null => null
boolean v => false => false
[Ljava.lang.reflect.Field;@79b8e47 [Ljava.lang.reflect.Field;@79b8e47 => undefined => undefined
[native function d() {
[native code]
} => undefined => undefined
*** entered com.miui.permcenter.privacymanager.k.a.a
arg[0]: com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity@1a85b4a => "<instance: android.content.Context, $className: com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity>"
java.lang.Throwable
at com.miui.permcenter.privacymanager.k.a.a(Native Method)
at com.miui.permcenter.privacymanager.k.a.<init>(Unknown Source:77)
at com.miui.permcenter.privacymanager.k.a.<init>(Native Method)
at com.miui.permcenter.privacymanager.behaviorrecord.c.a(Unknown Source:347)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity.a(Unknown Source:68)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity.a(Unknown Source:0)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity$m.z(Unknown Source:44)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity$m.z(Unknown Source:0)
at a.j.b.a.A(Unknown Source:0)
at c.c.d.n.c.A(Unknown Source:0)
at a.j.b.a$a.a(Unknown Source:2)
at a.j.b.a$a.a(Unknown Source:2)
at a.j.b.d$b.call(Unknown Source:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
retval: undefined => undefined
*** exiting com.miui.permcenter.privacymanager.k.a.a
========================================================================================================================================================================================================Inspecting Fields: => true => class com.miui.permcenter.privacymanager.k.a
java.lang.String a => undefined => undefined
java.lang.String b => undefined => undefined
java.lang.String c => undefined => undefined
long d => undefined => undefined
int e => undefined => undefined
int f => undefined => undefined
java.lang.String g => undefined => undefined
java.lang.String h => undefined => undefined
int i => undefined => undefined
int j => undefined => undefined
int k => undefined => undefined
java.lang.CharSequence l => undefined => undefined
java.lang.CharSequence m => undefined => undefined
java.lang.String n => undefined => undefined
int o => undefined => undefined
java.lang.String p => null => null
int q => 0 => 0
com.miui.appmanager.i r => null => null
int s => 0 => 0
java.lang.String t => null => null
java.util.List u => null => null
boolean v => false => false
[Ljava.lang.reflect.Field;@bc0f586 [Ljava.lang.reflect.Field;@bc0f586 => undefined => undefined
[native function d() {
[native code]
} => undefined => undefined
*** entered com.miui.permcenter.privacymanager.k.a.$init
arg[0]: com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity@1a85b4a => "<instance: android.content.Context, $className: com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity>"
arg[1]: com.tencent.mm => "com.tencent.mm"
arg[2]: com.tencent.mm => "com.tencent.mm"
arg[3]: null => "null"
arg[4]: 35184372088832 => "35184372088832"
arg[5]: 0 => 0
arg[6]: 1 => 1
arg[7]: 2022-12-30 09:40 => "2022-12-30 09:40"
arg[8]: 2022-12-30 09:40 => "2022-12-30 09:40"
arg[9]: 1 => 1
arg[10]: 0 => 0
arg[11]: 0 => 0
arg[12]: 0 => 0
java.lang.Throwable
at com.miui.permcenter.privacymanager.k.a.<init>(Native Method)
at com.miui.permcenter.privacymanager.behaviorrecord.c.a(Unknown Source:347)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity.a(Unknown Source:68)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity.a(Unknown Source:0)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity$m.z(Unknown Source:44)
at com.miui.permcenter.privacymanager.behaviorrecord.AppBehaviorRecordActivity$m.z(Unknown Source:0)
at a.j.b.a.A(Unknown Source:0)
at c.c.d.n.c.A(Unknown Source:0)
at a.j.b.a$a.a(Unknown Source:2)
at a.j.b.a$a.a(Unknown Source:2)
at a.j.b.d$b.call(Unknown Source:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
retval: undefined => undefined
*** exiting com.miui.permcenter.privacymanager.k.a.$init
其中的源码:
public static boolean a(Context arg35, String arg36, int arg37, @NonNull List arg38, int[] arg39) {
int v25;
Cursor v29_1;
String v22_1;
String v21_1;
int v20_1;
int v10_1;
List v2_2;
long v33;
int v32;
int v31_1;
int v23;
int v24;
int v3_2;
int v1_4;
int v7;
long v17;
String v5;
String v4_1;
Cursor v6;
String v22;
int v1_1;
StringBuilder v3_1;
String v4;
Cursor v29 = null;
Context v0 = arg35;
List v15 = arg38;
int[] v1 = arg39;
long v13 = System.currentTimeMillis();
boolean v16 = c.f(arg35);
String[] v2 = new String[]{"pkgName", "calleePkg", "permissionId", "mode", "processState", "startTime", "endTime", "count", "user"};
int v12 = 2;
String[] v3 = new String[2];
int v11 = 0;
v3[0] = arg36;
int v10 = 1;
v3[1] = String.valueOf(arg37);
int v9 = 4;
int v8 = 3;
if(v16) {
v2 = (String[])Arrays.copyOf(((Object[])v2), v2.length + 1);
v2[v2.length - 1] = "calleeUser";
v3 = new String[]{arg36, String.valueOf(arg37), arg36, String.valueOf(arg37)};
v4 = "(pkgName == ? AND user == ? ) OR ( calleePkg == ? AND calleeUser == ? )";
}
else {
v4 = "pkgName == ? AND user == ?";
}
String[] v19 = v2;
String[] v21 = v3;
String v20 = v4;
if(v1 == null) {
v22 = "endTime DESC , _id DESC";
}
else if(v1.length == 1) {
v3_1 = new StringBuilder();
v3_1.append("endTime DESC , _id DESC");
v3_1.append(" LIMIT ");
v1_1 = v1[0];
goto label_76;
}
else {
if(v1.length == 2) {
v3_1 = new StringBuilder();
v3_1.append("endTime DESC , _id DESC");
v3_1.append(" LIMIT ");
v3_1.append(v1[0]);
v3_1.append(" OFFSET ");
v1_1 = v1[1];
label_76:
v3_1.append(v1_1);
v22 = v3_1.toString();
goto label_83;
}
v22 = "endTime DESC , _id DESC";
}
label_83:
Cursor v1_2 = null;
try {
v6 = arg35.getContentResolver().query(PermissionContract.RECORD_URI, v19, v20, v21, v22);
goto label_91;
}
catch(Exception v0_1) {
}
catch(Throwable v0_2) {
v29 = v1_2;
miuix.core.util.d.a(v29);
throw v0_2;
}
boolean v31 = false;
goto label_260;
label_91:
if(v6 == null) {
v29_1 = v6;
v31 = false;
}
else {
boolean v1_3 = false;
try {
while(true) {
label_93:
boolean v2_1 = v6.moveToNext();
goto label_99;
}
}
catch(Exception v0_1) {
v29 = v6;
v31 = v1_3;
goto label_258;
label_99:
if(!v2_1) {
v29_1 = v6;
miuix.core.util.d.a(v29_1);
return v1_3;
}
try {
v4_1 = v6.getString(v11);
v5 = v6.getString(v10);
v17 = v6.getLong(v12);
v7 = v6.getInt(8);
}
catch(Exception v0_1) {
goto label_256;
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
if(v16) {
try {
v1_4 = v6.getInt(9);
goto label_113;
}
catch(Exception v0_1) {
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
v1_2 = v6;
v31 = (boolean)v10;
goto label_260;
label_113:
v3_2 = v1_4;
}
else {
v3_2 = arg37;
}
try {
boolean v1_5 = c.c(v5);
}
catch(Exception v0_1) {
goto label_256;
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
if(!v1_5) {
goto label_125;
}
try {
if(!c.e.containsKey(Long.valueOf(v17)) || (c.a(v0, v4_1, v7))) {
goto label_140;
}
label_125:
if(v1_5) {
goto label_149;
}
if(v17 == 2L && !c.g.containsKey(v4_1) || (c.a(v0, v5, v3_2))) {
goto label_140;
}
boolean v1_6 = c.a(v0, v4_1, v5);
}
catch(Exception v0_1) {
v1_2 = v6;
v31 = true;
goto label_260;
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
if(v1_6) {
label_140:
v29 = v6;
v24 = v8;
v23 = v9;
v31_1 = v11;
v32 = v12;
v33 = v13;
v2_2 = v15;
v19 = null;
goto label_273;
}
try {
label_149:
v10_1 = v6.getInt(v8);
v20_1 = v6.getInt(v9);
v21_1 = v6.getString(5);
v22_1 = v6.getString(6);
long v8_1 = c.a(v22_1);
if(v8_1 > v13) {
v29 = v6;
v31_1 = v11;
v32 = v12;
v33 = v13;
v2_2 = v15;
v19 = null;
v23 = 4;
v24 = 3;
goto label_273;
}
if(c.a(v13, v8_1) > 6) {
v29_1 = v6;
v31 = true;
goto label_288;
}
v25 = v17 == 0x20L ? 1 : v6.getInt(7);
if(v16) {
goto label_183;
}
else {
goto label_209;
}
goto label_231;
}
catch(Exception v0_1) {
goto label_256;
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
}
catch(Throwable v0_2) {
v29 = v6;
miuix.core.util.d.a(v29);
throw v0_2;
}
label_183:
Context v2_3 = arg35;
String v3_3 = arg36;
v29 = v6;
long v6_1 = v17;
v24 = 3;
int v8_2 = v10_1;
v23 = 4;
int v9_1 = v20_1;
v19 = null;
String v10_2 = v21_1;
v31_1 = v11;
String v11_1 = v22_1;
v32 = v12;
int v12_1 = v25;
v33 = v13;
int v13_1 = v7;
int v14 = v3_2;
List v0_3 = v15;
try {
super(v2_3, v3_3, v4_1, v5, v6_1, v8_2, v9_1, v10_2, v11_1, v12_1, v13_1, v14, 1);
Object v15_1 = null;
goto label_231;
label_209:
v29 = v6;
v31_1 = v11;
v32 = v12;
v33 = v13;
v0_3 = v15;
v19 = null;
v23 = 4;
v24 = 3;
v15_1 = new a(arg35, arg36, v4_1, v5, v17, v10_1, v20_1, v21_1, v22_1, v25, arg37, 1); // 初始化
label_231:
if(arg38.size() == 0) {
v0_3.add(v15_1);
v2_2 = v0_3;
v0 = arg35;
}
else {
v2_2 = v0_3;
v0 = arg35;
if(!((a)v0_3.get(arg38.size() - 1)).a(v0, ((a)v15_1))) {
v2_2.add(v15_1);
}
}
goto label_273;
}
catch(Exception v0_1) {
}
catch(Throwable v0_2) {
miuix.core.util.d.a(v29);
throw v0_2;
}
label_256:
v31 = v19;
label_258:
v1_2 = v29;
try {
label_260:
Log.e("BehaviorRecord-Utils", "loadAppBehaviorByPkgNameAndUser error", v0_1);
}
catch(Throwable v0_2) {
v29 = v1_2;
miuix.core.util.d.a(v29);
throw v0_2;
}
miuix.core.util.d.a(v1_2);
return v31;
miuix.core.util.d.a(v29);
throw v0_2;
label_273:
v15 = v2_2;
v1_3 = (int)v19;
v10 = (int)v1_3;
v9 = v23;
v8 = v24;
v6 = v29;
v11 = v31_1;
v12 = v32;
v13 = v33;
goto label_93;
}
label_288:
miuix.core.util.d.a(v29_1);
return v31;
}
调用的是这个函数
public a(Context arg3, String arg4, String arg5, String arg6, long arg7, int arg9, int arg10, String arg11, String arg12, int arg13, int arg14, int arg15)
v15_1 = new a(arg35, arg36, v4_1, v5, v17, v10_1, v20_1, v21_1, v22_1, v25, arg37, 1); // 初始化
public a(Context arg3, String arg4, String arg5, String arg6, long arg7, int arg9, int arg10, String arg11, String arg12, int arg13, int arg14, int arg15) { // 确定行为触发的包名和时间
public String a(Resources arg9) { // 确定行为类型,返回触发时间 “Restricted at 10:15”
整体思路,一个packager uid下调用某个隐私API都会被记录,并存放库中。
隐私沙箱两种方案:
- 更改art编译模式,trace只trace framework层内容,对特定UID的app进行改变art编译模式。
- 研究MIUI Privacy_Manager 隐私行为功能实现,仿照一份写出来trace。
改动art类似于插入式Hook,系统级改动,安全有效,但不确定是否会造成原本正常的app崩溃。
MIUI Privacy_Manager形式更可靠,但是无法选定哪一个UID,以及UID发送给Manager app如何处理。
上次实现的问题是,虽然可以直接改动相应的framework代码,做到那个地方调用,并且能将调用的堆栈,都能够发送,但是对调用的UID为止,并且无法指定UID进行控制,所以不是很符合我的要求。