PoomSmart/YTUHD

VP9 entitlement spoofing does not work on jailed environment

PoomSmart opened this issue ยท 17 comments

The technique relies on MSHookFunction() which does nothing on sideloaded apps. As a result, no hardware decoder has ever worked on sidedloaded YouTube. We may be able to use fishhook instead.

Based on your wording, does this mean that even H.264 on <= 1080p videos is using software decoding if YouTube is sideloaded?

@mihir-io H.264 isn't affected.

Any progress on this? Or is it simply not possible?

According to dyld source it is possible to replace functions in the shared cache with closures, not sure if it's possible to implement without a jailbreak though. Might be worth looking into

@level3tjg Curious if there are any existing sample projects out there.

@level3tjg Curious if there are any existing sample projects out there.

Turns out plain interposing (storing interposing tuples in __DATA,__interpose) should actually generate a closure with the correct patch entries, however it only applies patches to the cache from the main executable's closure and when I tried it didn't seem to work. Fugu14 exploited a bug in dyld to pre-generate a closure to inject code into some processes but it looks like it was patched in 14.7

From Closure.h:

     Dyld cache patching notes:

     The dyld cache needs to be patched to support interposing and dylib "roots".

     For cached dylibs overrides:
         Closure build time:
             1) LoadedImages will contain the new dylib, so all symbol look ups
                will naturally find new impl.  Only dyld cache needs special help.
             2) LoadedImages entry will have flag for images that override cache.
             3) When setting Closure attributes, if flag is set, builder will
                iterate PatchableExport entries in Image* from cache and create
                a PatchEntry for each.
         Runtime:
             1) [lib]dyld will iterate PatchEntry in closure and patch cache

     For interposing:
         Closure build time:
             1) After Images built, if __interpose section(s) exist, builder will
                build InterposingTuple entries for closure
             2) For being-built closure and launch closure, apply any InterposingTuple
                to modify Image fixups before Image finalized.
             3) Builder will find PatchableExport entry that matchs stock Impl
                and add PatchEntry to closure for it.
         Runtime:
             1) When closure is loaded (launch or dlopen) PatchEntries are
                applied (exactly once) to whole cache.
             2) For each DlopenClosure loaded, any InterposeTuples in *launch* closure
                are applied to all new images in new DlopenClosure.

     For weak-def coalesing:
          Closure build time:
             1) weak_bind entries are turned into -3 ordinal lookup which search through images
                in load order for first def (like flat). This fixups up all images not in cache.
             2) When processing -3 ordinals, it continues past first found and if any images
                past it are in dyld cache and export that same symbol, a PatchEntry is added to
                closure to fix up all cached uses of that symbol.
             3) If a weak_bind has strong bit set (no fixup, just def), all images from the dyld
                cache are checked to see if the export that symbol, if so, a PatchEntry is added
                to the closure.
          Runtime:
             1) When closure is loaded (launch or dlopen) PatchEntries are
                applied (exactly once) to whole cache.

Calling FigServer_Initialize() at any point before a decoder instance is created will skip the VP9 entitlement checks, however video playback still returns AVErrorDecoderNotFound.

Well it is still tricky to bypass VP9 checks from inside YouTube app because the function is unnamed.

image

It should pass YT checks since VTIsHardwareDecodeSupported will return true for VP9. FigServer_Initialize sets a flag in CoreMedia that says it's running inside mediaserverd, skipping the entitlement check.

VTIsHardwareDecodeSupported

If VTSelectAndCreateVideoDecoderInstance succeeds then all of the checks pass and a decoder instance is created and added to VT's decoder registry. I've verified that VP9 is in the decoder registry so I'm not sure why I'm seeing AVErrorDecoderNotFound in the YT player.

@level3tjg Interesting. Can you maybe share the code about FigServer_Initialize so I may try on my own devices?

FigServer_Initialize writes to gIsMediaserverd and FigServer_IsServerProcess reads it, that's all.

image

@level3tjg So how do you get the symbol for FigServer_Initialize ? dlsym ? MSFindSymbol ?

@PoomSmart I linked against CoreMedia and declared it as an external function

@level3tjg I believe your trick introduces a side effect when VP9 decompression session is being created from YouTube app - it won't communicate to mediaserverd correctly anymore.

image

I don't think that's the case, even if you bypass the entitlement check by other means (with a jailbreak but sideloaded app) you'll still get the same outcome.

I see. That probably means you tested hooking entitlement check function directly too.

There are additional entitlement checks performed by FigVideoQueueRemoteServer_Create within mediaserverd ๐Ÿ™