Genymobile / scrcpy

Display and control your Android device
Apache License 2.0
105.26k stars 10.22k forks source link

Optional root (su, Magisk Zygisk module, etc) for mirroring Android 12+ w/FLAG_SECURE #3049

Open digitalcircuit opened 2 years ago

digitalcircuit commented 2 years ago

I found https://github.com/Genymobile/scrcpy/issues/2242 but that seemed to focus on non-root options.

Is your feature request related to a problem? Please describe. In Android 12+, it is no longer possible to mirror the output of apps expecting a FLAG_SECURE display. The non-root fix scrcpy uses now is to no longer capture secure output on Android 12+.

Describe the solution you'd like For those with root, it'd be nice if scrcpy could optionally make use of root access to enable mirroring apps that require secure display output.

Brainstorming:

Describe alternatives you've considered Disable FLAG_SECURE for all apps using the LSposed (modern Xposed), or via a Magisk "Zygisk" code injection to the system framework.

This would unfortunately enable every app to have this access instead of just allowing the shell, unless a module could be made to revert specifically the shell UID FLAG_SECURE check.

Additional context All of this except for maybe using su directly if possible sounds rather complicated for a niche of scrcpy users. I'd understand if the immediate reaction to this feature request is to close it and go "Nope, not touching that." :slightly_smiling_face:

rom1v commented 2 years ago

I have no experience with Magisk, but if it's possible to only allow shell to enable secure flag permissions, then scrcpy could provide an option --secure-flag, which will cause an exception (like #2129) on non-root devices, but will work for root devices with permissions enabled.

AndroidDeveloperLB commented 2 years ago

Wait, it's now possible to use ScrCpy to enable mirroring even protected screens (on rooted devices) ? Is it under development?

digitalcircuit commented 2 years ago

@AndroidDeveloperLB Not yet, alas. That's why I'm filing this feature request, to prompt discussion about how scrcpy could possibly do this.

@rom1v Noted! Adding a --secure-flag option once a root/Magisk solution is sorted to reverse that permission change sounds like a reasonable low-maintenance approach on scrcpy's side.

Rambling notes

I have much to learn about Magisk's recent Zygisk development and hooking Android functions, but I wanted to jot this down for future reference.

It looks like it'd involve patching the hasCaptureBlackoutContentPermission() function

static bool hasCaptureBlackoutContentPermission() {
    IPCThreadState* ipc = IPCThreadState::self();
    const int pid = ipc->getCallingPid();
    const int uid = ipc->getCallingUid();
    return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
            PermissionCache::checkPermission(sCaptureBlackoutContent, pid, uid);
}

Adding back in a || uid == AID_SHELL like what used to be there.

Alternatively, if there's a way to use root/Magisk/etc to grant android.permission.CAPTURE_BLACKOUT_CONTENT to scrcpy, that would work. It might involve using the Shizuku API within scrcpy itself via Sui, which is… probably lower level than desired?

(I may have gotten the permission name wrong - the system AndroidManifest.xml seems to describe this as capturing secure content, as if a screenshot.)

Regardless, I'd understand wanting to keep the changes to scrcpy itself as minimal (and therefore as maintainable) as possible.

AndroidDeveloperLB commented 2 years ago

@digitalcircuit What's "CAPTURE_BLACKOUT_CONTENT" ? I don't see it on the docs: https://developer.android.com/reference/android/Manifest.permission I wonder if a screenshot app could get this permission (via root).

Anyway, I would love to have ScrCpy be able to show this content, even it if requires root. I find it weird that this restriction is applied even via adb.

digitalcircuit commented 2 years ago

@AndroidDeveloperLB I think it's intentionally not mentioned on that page due to being listed as "Not for use by third-party applications." with an @hide annotation.

frameworks/base/core/res/AndroidManifest.xml found via searching on cs.android.com:

    <!-- Allows an application to take screenshots of layers that normally would be blacked out when
         a screenshot is taken. Specifically, layers that have the flag
         {@link android.view.SurfaceControl#SECURE} will be screenshot if the caller requests to
         capture secure layers. Normally those layers will be rendered black.
         <p>Not for use by third-party applications.
         @hide
    -->
    <permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"
        android:protectionLevel="signature" />

As you mentioned, the question I have as well is whether a protection level of signature can be safely granted to just a specific app via root/Sui/Zygisk/etc? And if so, what would be the proper (most maintainable and secure) method of going about it..?

Alternatively, hijacking the hasCaptureBlackoutContentPermission() permission check to allow UID_SHELL (ADB) again might return to pre-Android 12 security level - less specific, but likely an acceptable trade-off.

(It's possible I'm misunderstanding as I'm attempting to make sense of an area of Android that I'm unfamiliar with.)

AndroidDeveloperLB commented 2 years ago

@digitalcircuit According to CommonsWare, it shouldn't allow you to grant it, sadly: https://stackoverflow.com/questions/29185717/is-there-any-way-to-get-permission-with-protection-level-signature-in-android#comment46586830_29185717

But you can try. Edit some open sourced screenshot app, add the permission, grant it via adb, and see if it helps on protected apps.

He't talking about normal granting of the permission via adb (or root). I don't know the advanced stuff you talk about

MlgmXyysd commented 2 years ago

It's not a good thing to require root permission. Hook (Zygisk/Xposed) is even worse, especially when Xposed is seriously deprecated and destroying the custom Android community (not modern). Why not try to use the normal application to ask for permission of virtual display?

AndroidDeveloperLB commented 2 years ago

@MlgmXyysd You'd have to talk with every application that uses this API to block screenshots/screen-capture... And it's not guaranteed they will do anything about what you write them. Not practical.

It's better to have some solution than nothing.

I've requested from Google to add some toggle to turn off this kind of protection in next Android version: https://issuetracker.google.com/issues/225529536 Please consider starring.

MlgmXyysd commented 2 years ago

I've requested from Google to add some toggle to turn off this kind of protection in next Android version: https://issuetracker.google.com/issues/225529536 Please consider starring.

Starred, but there is no hope that they will do so, just as they added FLAG_SECURE.

LexNastin commented 1 year ago

Any progress or plans on this? Would really love a way to bypass FLAG_SECURE

MlgmXyysd commented 1 year ago

Any progress or plans on this? Would really love a way to bypass FLAG_SECURE

You can use other ROMs that allows the user to ignore FLAG_SECURE, such as KaleidoscopeOS.

opptimus commented 1 year ago

Wait, it's now possible to use ScrCpy to enable mirroring even protected screens (on rooted devices) ? Is it under development?

I also neet this feature!

AndroidDeveloperLB commented 1 year ago

It seems that if your device is rooted with Magisk, you can have "Zygisk - LSPosed" module, and using it, there is a module inside that is called "Disable FLAG_SECURE":

image

image

LexNastin commented 1 year ago

It seems that if your device is rooted with Magisk, you can have "Zygisk - LSPosed" module, and using it, there is a module inside that is called "Disable FLAG_SECURE":

image

image

Your proposed solution sadly won't work for most use cases, as this would normally be needed for things like banking apps, but they need to be in the DenyList to work, preventing any modifications to them. So this won't work for that, and we need to modify/use a different service which doesn't have to be DenyListed, the secure display being one of them. Root support would be a very nice feature for scrcpy to have, and I don't believe it would take too much effort to implement. Thanks!

AndroidDeveloperLB commented 1 year ago

... Your proposed solution sadly won't work for most use cases, as this would normally be needed for things like banking apps, but they need to be in the DenyList to work, preventing any modifications to them. So this won't work for that, and we need to modify/use a different service which doesn't have to be DenyListed, the secure display being one of them. Root support would be a very nice feature for scrcpy to have, and I don't believe it would take too much effort to implement. Thanks!

Maybe. I haven't had an issue with this so far. If you wish, I can test it on specific apps that everyone can check, and I could tell you what I find Of course, the best thing is to have ScrCpy handle it on its own, overcoming all issues.

MlgmXyysd commented 1 year ago

It seems that if your device is rooted with Magisk, you can have "Zygisk - LSPosed" module, and using it, there is a module inside that is called "Disable FLAG_SECURE":

More easily to detect root lol

AndroidDeveloperLB commented 1 year ago

Guys I know this issue. I just wrote for other cases, when it does work fine.

fcaronte commented 1 year ago

So guy's no way for a fix? I arrived from an evox rom were is a stock feature and now i miss it

Ch4m311eom commented 1 year ago

Check this out https://forum.xda-developers.com/t/module-disable-flag-secure-v5-0-by-mehedi-h-joy.4490475/ It's a Magisk module which doesn't need LSPosed. I can confirm it works on Android 12 and Samsung One UI 4.1

LexNastin commented 1 year ago

Please read my earlier comment @Ch4m311eom, I’m almost certain it still applies based on the nature of the new DenyList functionality.

Ch4m311eom commented 1 year ago

Hmm I just checked this module with Shamiko and UniversalSafetyNet Fix and everything seems to be fine. I'm able to add card to Google Pay and launch my banking app. Of course I had to add banking app to DenyList list but when it's paired with Shamiko I can't see any problem. The only disadvantage is that my phone (SM-G975F) falls in a bootloop everytime I install any Magisk module when DisableFlagSecure is installed. To install any module I have to remove DisableFlagSecure, install new module and then install DisableFlagSecure back.

LexNastin commented 1 year ago

What I’m saying in that comment is that if an app is in the DenyList, DisableFlagSecure won’t have any effect on that app, and you still won’t be able to take any screenshots in it. AOSPMods can be used to solve this entire issue now though.

Ch4m311eom commented 1 year ago

Oh, I get it. Personally I only had to "uncover" Bitwarden, that's why I found no issue.

RiggiG commented 1 year ago

All of this Magisk talk seems to be vastly overcomplicating things from where I sit - since that would suggest you've got root, it'd be infinitely simpler to just execute the server as AID_SYSTEM (permitted to display FLAG_SECURE content) by adding in su 1000 -c to the startup argument list here. I did try 1003 for AID_GRAPHICS which also worked for video, but lacked permissions for basically everything else.

With this simple change, I've verified functionality with mirroring such an app on Android 13. Of course, to add this to production, this changeup should be from a flag passed on the client (--as-root or something along those lines) alongside a warning to only grant root once to the adb shell process, but in the meantime users with root should be able to just use these binaries instead.

It also quite possibly breaks other things, but on my A13 Pixel 5 the audio, video, and touch are working without issue. Release is here.

diogotcorreia commented 1 year ago

I confirm it works on my device as well (Xiaomi 11T Pro with Pixel Experience 12 GSI) on a Linux x86_64 host. Thank you a lot @RiggiG!

@rom1v What do you think about @RiggiG's solution? I don't mind submitting a pull request to add their solution behind a flag (what would you like the flag to be? --as-root, --secure-flag, or other?) if both of you agree (I don't want to steal @RiggiG's work).

rom1v commented 1 year ago

I think it is an acceptable solution, it's quite simple and non invasive. --as-root or --root look good to me, what do other people think?

RiggiG commented 1 year ago

I'd certainly have no qualms with anyone else submitting a PR for bringing this in (of course via a default-inactive flag) - this was just a quick PoC to verify it was as simple as I thought it was after reading these issues. I'm also intending to try (I am woefully ill-equipped to jump into Android development) background camera access + streaming via this root mode.

I like --as-root for clarity, but certainly wouldn't call --root unclear and I'll never complain about a more concise flag.

rom1v commented 1 year ago

I'm also intending to try (I am woefully ill-equipped to jump into Android development) background camera access + streaming via this root mode.

Note that since Android 11 (commit 393ad6e0ad1670a1d33e97f7bb07b0df381b5e76), shell has CAMERA permission: https://github.com/aosp-mirror/platform_frameworks_base/blob/de002b7c953d64125ee3088dd4bf16c28a64c5ba/packages/Shell/AndroidManifest.xml#L290

So it is certainly possible to capture the device camera without root (an option --video-source=camera similar to --audio-source=mic would be neat).

yume-chan commented 12 months ago

I quickly put together some code to test camera capturing: https://github.com/Genymobile/scrcpy/compare/dev...yume-chan:scrcpy:feat/camera?expand=1, it works on my Mi 11 (MIUI 14, Android 13).

So besides --video-source=camera, it also needs --camera=<id> and --list-cameras.

--video-source=camera will imply --no-control, touch injection is not possible due to lack of screen size, keyboard injection also doesn't make much sense. Maybe clicking will change the focus region.

Taking screenshot (https://github.com/Genymobile/scrcpy/pull/2040) will be useful in camera mode.

rom1v commented 12 months ago

Awesome :+1: That was quick after my previous message (https://github.com/Genymobile/scrcpy/issues/3516#issuecomment-1625585175) :smile:

So besides --video-source=camera, it also needs --camera= and --list-cameras.

Yes, and also maybe a constant in addition for front and back (so that users don't have to look for the id).

Something like:

for (String cameraId : cameraManager.getCameraIdList()) {
    CameraCharacteristics cc = cameraManager.getCameraCharacteristics(cameraId);
    int lensFacing = cc.get(CameraCharacteristics.LENS_FACING);
    if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
        // …
    }
}

As a side note, maybe another possible option (but less important) would be the parameter passed to camera.createCaptureRequest(…); (at least TEMPLATE_PREVIEW for lower latency) or TEMPLATE_RECORD).

ObsydianBlackKnight commented 7 months ago

Are there any news on supporting root to elude FLAG_SECURE?

vvb2060 commented 1 month ago

4947

only server, so magisk is not supported, only userdebug build ROM can use

Adityashaw commented 1 week ago

I like --as-root for clarity, but certainly wouldn't call --root unclear and I'll never complain about a more concise flag.

I built your dev branch from https://github.com/RiggiG/scrcpy-root.git but running ./run x --root still had black screen.

(I granted root permission to shell on magisk pop up)

Any pointers @RiggiG ?