前言 一直好奇,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下吧
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 *** 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
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 *** 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
其中的源码:
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 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 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进行控制,所以不是很符合我的要求。