66import android .os .Build ;
77
88import com .sevtinge .hyperceiler .common .log .XposedLog ;
9- import com .sevtinge .hyperceiler .libhook .callback .IMethodHook ;
109import com .sevtinge .hyperceiler .libhook .utils .hookapi .tool .EzxHelpUtils ;
1110
1211import java .lang .reflect .Field ;
1615import java .util .function .BiConsumer ;
1716import java .util .function .BiPredicate ;
1817
19- import io .github .kyuubiran . ezxhelper . xposed . common . HookParam ;
18+ import io .github .libxposed . api . XposedInterface ;
2019import io .github .libxposed .api .XposedModuleInterface ;
2120
2221public class FlagSecure {
@@ -25,6 +24,11 @@ public class FlagSecure {
2524
2625 private static Field captureSecureLayersField ;
2726
27+ @ FunctionalInterface
28+ private interface ChainHooker {
29+ Object intercept (XposedInterface .Chain chain ) throws Throwable ;
30+ }
31+
2832 public void onLoad (XposedModuleInterface .SystemServerStartingParam lpparam ) {
2933 var classLoader = lpparam .getClassLoader ();
3034
@@ -34,153 +38,111 @@ public void onLoad(XposedModuleInterface.SystemServerStartingParam lpparam) {
3438 XposedLog .e (TAG , "system" , "deoptimize system server failed" , t );
3539 }
3640
41+ // Screen record detection (V~Baklava)
3742 try {
3843 hookWindowManagerService (classLoader );
3944 } catch (Throwable t ) {
4045 XposedLog .e (TAG , "system" , "hook WindowManagerService failed" , t );
4146 }
4247
48+ // Screenshot detection (U~Baklava)
4349 try {
4450 hookActivityTaskManagerService (classLoader );
4551 } catch (Throwable t ) {
4652 XposedLog .e (TAG , "system" , "hook ActivityTaskManagerService failed" , t );
4753 }
4854
55+ // Xiaomi HyperOS (U~Baklava)
4956 try {
5057 hookHyperOS (classLoader );
5158 } catch (ClassNotFoundException ignored ) {
5259 } catch (Throwable t ) {
5360 XposedLog .e (TAG , "system" , "hook HyperOS failed" , t );
5461 }
5562
63+ // ScreenCapture in WindowManagerService (S~Baklava)
5664 try {
5765 hookScreenCapture (classLoader );
5866 } catch (Throwable t ) {
5967 XposedLog .e (TAG , "system" , "hook ScreenCapture failed" , t );
6068 }
6169
70+ // WifiDisplay (S~Baklava) / OverlayDisplay (S~Baklava) / VirtualDisplay (U~Baklava)
6271 try {
6372 hookDisplayControl (classLoader );
6473 } catch (Throwable t ) {
6574 XposedLog .e (TAG , "system" , "hook DisplayControl failed" , t );
6675 }
6776
77+ // VirtualDisplay with MediaProjection (S~Baklava)
6878 try {
6979 hookVirtualDisplayAdapter (classLoader );
7080 } catch (Throwable t ) {
7181 XposedLog .e (TAG , "system" , "hook VirtualDisplayAdapter failed" , t );
7282 }
7383
84+ // secureLocked flag
7485 try {
7586 hookWindowState (classLoader );
7687 } catch (Throwable t ) {
7788 XposedLog .e (TAG , "system" , "hook WindowState failed" , t );
7889 }
7990 }
8091
81- private final IMethodHook createDisplayHooker = new IMethodHook () {
82- @ Override
83- public void before (HookParam callback ) {
84- if (Build .VERSION .SDK_INT < Build .VERSION_CODES .UPSIDE_DOWN_CAKE ) {
85- var stackTrace = new Throwable ().getStackTrace ();
86- for (int i = 4 ; i < stackTrace .length && i < 8 ; i ++) {
87- var name = stackTrace [i ].getMethodName ();
88- if (name .equals ("createVirtualDisplayLocked" )) {
89- return ;
90- }
91- }
92- }
93- callback .getArgs ()[1 ] = true ;
94- }
92+ private final ChainHooker createDisplayHooker = chain -> {
93+ Object [] args = chain .getArgs ().toArray ();
94+ args [1 ] = true ;
95+ return chain .proceed (args );
9596 };
9697
97- private final IMethodHook checkPermissionHooker = new IMethodHook () {
98- @ Override
99- public void before (HookParam callback ) {
100- var permission = callback .getArgs ()[0 ];
101- if ("android.permission.CAPTURE_BLACKOUT_CONTENT" .equals (permission )) {
102- callback .getArgs ()[0 ] = "android.permission.READ_FRAME_BUFFER" ;
98+ private final ChainHooker screenCaptureHooker = chain -> {
99+ var captureArgs = chain .getArg (0 );
100+ try {
101+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .BAKLAVA && isAtLeastBaklava1 ()) {
102+ captureSecureLayersField .set (captureArgs , 1 );
103+ } else {
104+ captureSecureLayersField .set (captureArgs , true );
103105 }
106+ } catch (IllegalAccessException t ) {
107+ XposedLog .e (TAG , "system" , "ScreenCaptureHooker failed" , t );
104108 }
109+ return chain .proceed ();
105110 };
106111
107- private final IMethodHook oplusScreenCaptureHooker = new IMethodHook () {
108- @ Override
109- public void before (HookParam callback ) {
110- callback .getArgs ()[0 ] = -1 ;
112+ private final ChainHooker createVirtualDisplayLockedHooker = chain -> {
113+ var caller = (int ) chain .getArg (2 );
114+ if (caller >= 10000 && chain .getArg (1 ) == null ) {
115+ // not os and not media projection
116+ return chain .proceed ();
111117 }
112- };
113-
114- private final IMethodHook screenCaptureHooker = new IMethodHook () {
115- @ Override
116- public void before (HookParam callback ) {
117- var captureArgs = callback .getArgs ()[0 ];
118- try {
119- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .BAKLAVA && isAtLeastBaklava1 ()) {
120- captureSecureLayersField .set (captureArgs , 1 );
121- } else {
122- captureSecureLayersField .set (captureArgs , true );
123- }
124- } catch (IllegalAccessException t ) {
125- XposedLog .e (TAG , "system" , "ScreenCaptureHooker failed" , t );
118+ for (int i = 3 ; i < chain .getArgs ().size (); i ++) {
119+ var arg = chain .getArg (i );
120+ if (arg instanceof Integer ) {
121+ var flags = (int ) arg ;
122+ flags |= DisplayManager .VIRTUAL_DISPLAY_FLAG_SECURE ;
123+ Object [] args = chain .getArgs ().toArray ();
124+ args [i ] = flags ;
125+ return chain .proceed (args );
126126 }
127127 }
128+ XposedLog .e (TAG , "system" , "flag not found in CreateVirtualDisplayLockedHooker" );
129+ return chain .proceed ();
128130 };
129131
130- private final IMethodHook createVirtualDisplayLockedHooker = new IMethodHook () {
131- @ Override
132- public void before (HookParam callback ) {
133- var caller = (int ) callback .getArgs ()[2 ];
134- if (caller >= 10000 && callback .getArgs ()[1 ] == null ) {
135- return ;
136- }
137- for (int i = 3 ; i < callback .getArgs ().length ; i ++) {
138- var arg = callback .getArgs ()[i ];
139- if (arg instanceof Integer ) {
140- var flags = (int ) arg ;
141- flags |= DisplayManager .VIRTUAL_DISPLAY_FLAG_SECURE ;
142- callback .getArgs ()[i ] = flags ;
143- return ;
144- }
145- }
146- XposedLog .e (TAG , "system" , "flag not found in CreateVirtualDisplayLockedHooker" );
147- }
132+ private final ChainHooker secureLockedHooker = chain -> {
133+ var walker = StackWalker .getInstance ();
134+ var match = walker .walk (frames -> frames
135+ .map (StackWalker .StackFrame ::getMethodName )
136+ .limit (10 )
137+ .skip (6 )
138+ .anyMatch (s -> s .equals ("setInitialSurfaceControlProperties" ) || s .equals ("createSurfaceLocked" )));
139+ if (match ) return chain .proceed ();
140+ return false ;
148141 };
149142
150- private final IMethodHook secureLockedHooker = new IMethodHook () {
151- @ Override
152- public void before (HookParam callback ) {
153- var walker = StackWalker .getInstance ();
154- var match = walker .walk (frames -> frames
155- .map (StackWalker .StackFrame ::getMethodName )
156- .limit (6 )
157- .skip (2 )
158- .anyMatch (s -> s .equals ("setInitialSurfaceControlProperties" ) || s .equals ("createSurfaceLocked" )));
159- if (match ) return ;
160- callback .setResult (false );
161- }
162- };
163-
164- private final IMethodHook returnTrueHooker = new IMethodHook () {
165- @ Override
166- public void before (HookParam callback ) {
167- callback .setResult (true );
168- }
169- };
170-
171- private final IMethodHook returnFalseHooker = new IMethodHook () {
172- @ Override
173- public void before (HookParam callback ) {
174- callback .setResult (false );
175- }
176- };
143+ private final ChainHooker returnFalseHooker = chain -> false ;
177144
178- private final IMethodHook returnNullHooker = new IMethodHook () {
179- @ Override
180- public void before (HookParam callback ) {
181- callback .setResult (null );
182- }
183- };
145+ private final ChainHooker returnNullHooker = chain -> null ;
184146
185147 private void deoptimizeSystemServer (ClassLoader classLoader ) throws ClassNotFoundException {
186148 deoptimizeMethods (
@@ -259,33 +221,20 @@ private void hookWindowManagerService(ClassLoader classLoader) throws ClassNotFo
259221 hook (method , returnFalseHooker );
260222 }
261223
262- private void hookActivityManagerService (ClassLoader classLoader ) throws ClassNotFoundException , NoSuchMethodException {
263- var activityTaskManagerServiceClazz = classLoader .loadClass ("com.android.server.am.ActivityManagerService" );
264- var method = activityTaskManagerServiceClazz .getDeclaredMethod ("checkPermission" , String .class , int .class , int .class );
265- hook (method , checkPermissionHooker );
266- }
267-
268224 private void hookHyperOS (ClassLoader classLoader ) throws ClassNotFoundException {
269225 var windowManagerServiceImplClazz = classLoader .loadClass ("com.android.server.wm.WindowManagerServiceImpl" );
270226 hookMethods (windowManagerServiceImplClazz , returnFalseHooker , "notAllowCaptureDisplay" );
271227 }
272228
273- private void hookScreenshotHardwareBuffer (ClassLoader classLoader ) throws ClassNotFoundException , NoSuchMethodException {
274- var screenshotHardwareBufferClazz = classLoader .loadClass (
275- "android.window.ScreenCapture$ScreenshotHardwareBuffer" );
276- var method = screenshotHardwareBufferClazz .getDeclaredMethod ("containsSecureLayers" );
277- hook (method , returnFalseHooker );
278- }
279-
280- private void hookMethods (Class <?> clazz , IMethodHook hooker , String ... names ) {
229+ private void hookMethods (Class <?> clazz , ChainHooker hooker , String ... names ) {
281230 List <String > list = Arrays .asList (names );
282231 Arrays .stream (clazz .getDeclaredMethods ())
283232 .filter (method -> list .contains (method .getName ()))
284233 .forEach (method -> hook (method , hooker ));
285234 }
286235
287- private void hook (Method method , IMethodHook hooker ) {
288- EzxHelpUtils .hookMethod (method , hooker );
236+ private void hook (Method method , ChainHooker hooker ) {
237+ EzxHelpUtils .chain (method , hooker :: intercept );
289238 }
290239
291240 private static boolean isAtLeastBaklava1 () {
0 commit comments