IOMobileFramebufferGetLayerDefaultSurface在iOS 9上无法正常工作

6
我的主要问题是,我如何反向工程一个已经存在但在新版本iOS中已被修改的私有API函数?
我创建了一个iOS应用程序来使用IOSurface和IOMobileFramebuffer记录屏幕内容。打开framebuffer的主要函数是IOMobileFramebufferGetMainDisplay(connect)IOMobileFramebufferGetLayerDefaultSurface
这些函数从应用程序的第一个版本开始就被使用,并且在所有iOS 7和8的版本上都可以正常工作。然而,在最新的iOS 9 beta(即beta 5)上,函数IOMobileFramebufferGetLayerDefaultSurface不起作用。该函数没有返回0,当成功打开framebuffer时应该返回0。
StackOverflow上的另一个用户似乎也遇到了同样的问题:IOMobileFramebufferGetLayerDefaultSurface function failed on iOS 9。我们有一个名为“_framebufferConnection”的IOMobileFramebufferConnection引用和一个名为“_screenSurface”的IOSurfaceRef。以下是当前的代码: IOMobileFramebufferGetMainDisplay(&_framebufferConnection); IOMobileFramebufferGetLayerDefaultSurface(_framebufferConnection, 0, &_screenSurface; 如前所述,这些在iOS 7-8上完美运行,但在iOS 9上,第二个函数会崩溃。我还查看了具有符号的两个版本的二进制文件并进行了比较。与iOS 8.4.1二进制文件相比,LDR的第二个参数在iOS 9中略有不同。因此,回到主要问题,我如何反向工程IOMobileFramebufferGetLayerDefaultSurface,或者看看它在iOS 9上实际上是如何被修改的?

你使用的是哪个iOS9版本? - user5273256
iOS 9 beta 5。但是在所有的iOS 9 beta/版本中都会出现相同的情况。 - Pyrology
4个回答

10
为了回答“iOS 9 实际上是如何修改的”的问题,我在 iOS8 和 iOS9(GM) 上进行了关于 IOMobileFramebufferGetLayerDefaultSurface 的调查。以下是我发现的结果:
安装: IOMobileFramebufferRef fb; IOMobileFramebufferGetMainDisplay(&fb);
iOS8 实现: 调用 kern_GetLayerDefaultSurface 通过 IOSurfaceID 访问底层 IOConnection IOSurfaceID surfaceID; uint32_t outCount = 1; IOConnectCallScalarMethod(fbConnect, 3, {0,0},2,&surfaceID,&outCount) 返回 IOSurfaceLookup (surfaceID)
iOS9 实现: 除了返回值之外,与上述相同 然后尝试检索 mach 端口以访问表面 io_service_t fbService = *(io_service_t *)((char *)fb + 16) mach_port_t surfacePort; IOServiceOpen(fbService, mach_task_self(), 3, &surfacePort) 成功后,返回 IOSurfaceLookupFromMachPort(surfacePort)在最后一步中,IOServiceOpen 返回错误 0x2c7(不支持的功能)。请注意,连接类型的第三个参数为 3,而不是打开帧缓冲服务时通常的 0。几乎可以确定,这种新的连接类型具有权限限制,防止除 Apple 之外的任何人检索 mach 端口以访问 IOMFB 表面。
有趣的是,调用 IOConnectCallScalarMethod 仍然可以用于检索 IOMFB 表面的 ID。但是,它不能再使用 IOSurfaceLookup 访问表面,因为该表面不再是全局的。这有点令人惊讶,因为它最初是全局的!
希望这有助于解释为什么 IOMFB 不能再用于记录屏幕。
来源:我在运行 iOS 8.4 的 iPhone6 和运行 iOS9 GM 的 iPhone6+ 上使用 LLDB。

我怀疑苹果以某种方式将其锁定了...是否有其他方法可以捕获IOSurface而不使用IOMobileFramebuffer,或者是否有其他框架可以代替它使用? - anthonya1999
1
@anthonya1999 我不知道有什么方法可以在你的应用程序在后台时记录屏幕。如果您想要录制您的应用程序,您可以使用公共的 drawViewHierarchyInRect: UIView 方法。这种方法也是App Store安全的,尽管我怀疑在您的情况下这并不重要。 - jvisenti
@DuncanC 我认为这很可能有一个相应的授权。我猜我们会在有人可以访问越狱的iOS9设备后知道答案。然而,AirPlay屏幕镜像是一种不同的动物,似乎使用虚拟显示器。当通过AirPlay进行镜像时,系统日志如下所示: mediaserverd[23] : [AirPlayEndpointScreen] 屏幕启动 backboardd[57] : IOMFB设置虚拟模式:0 0 - jvisenti
是的。我为目前的客户所做的工作基本上被卡住了,直到我们获得iOS 9越狱的访问权限,这样我们才能进行调查。越狱不是最终产品的选择,但私有API是一个选择,如果我们能找到一个授权,可能我们可以自己解锁它。 - Duncan C
@DuncanC 我也有同感。我实际上制作了iRec,这是一个iOS 7-8的屏幕录像机,因此在没有任何当前捕获屏幕缓冲区的方法的情况下,我自己被卡住了。试图想出另一种方法或绕过这些限制的方法。 - anthonya1999
显示剩余2条评论

5
我相信@nevyn是正确的。但是,我想再详细阐述一下。我已经广泛研究了这个确切的问题,并且IOMobileFramebufferGetLayerDefaultSurface函数确实返回-536870201,而如果它在没有任何问题的情况下运行该函数,则应返回0。这个错误在互联网上是存在的,但它只出现在用户遇到QuickTime的一般问题时。可能是苹果确实完全锁定了框架,并需要一个仅限于苹果的资格来访问帧缓冲区。我们无法添加这些资格,因为它也必须在供应配置文件中。我目前正在尝试阅读和解释反汇编并对IOMobileFramebuffer二进制文件进行一些逆向工程工作,以查看自上一个iOS版本以来是否有任何参数更改。如果我发现任何信息,我肯定会更新这个答案。但是,如果是这种情况,我建议尝试找到另一种捕获/记录屏幕内容的方法。

-更新-

似乎有证据表明,如果您阅读this,它显示完全相同的错误代码,这意味着该函数是“不受支持的”,并返回IOKit错误。至少我们现在知道了这是什么意思。然而,我仍然不确定如何修复它或使函数正常工作。我将继续研究这个问题。
更新2
实际上,我在iOS 9中发现了一个全新的类“FigScreenCaptureController”,它是MediaToolbox框架的一部分!但奇怪的是,为什么苹果只在iOS 9中包含它呢?因此,也许会有一种通过this来记录显示的方法……我很快将更深入地研究这个类。

嘿@anthonya1999,使用FigScreenCaptureController捕获屏幕有什么进展吗? - Shirish Kamath
@ShirishKamath 我知道这是一个晚回复,但我已经在类中查找了一下,你可以很好地调用开始/停止捕获,但我不知道如何设置它(即视频路径、帧速率等)。我将继续看看我能做些什么... - anthonya1999

2

并不完全正确 - 这只是一个权限问题,如果您转储kext,您会看到:

$ jtool -d __TEXT.__cstring 97.IOMobileGraphicsFamily.kext | grep com.apple
0xffffff80220c91a2: com.apple.private.allow-explicit-graphics-priority

如果您使用此方法进行自签名(jtool --sign --ent),一切都将正常工作。
这意味着在非越狱设备上您无法使用它。但是通过越狱,强大的功能再次回到了您的手中。

谢谢,我如何为越狱插件签名? - Suge

0

在iOS 9中,IOMobileFramebuffer已完全被封锁,不再可以从非苹果应用中使用。据我所知,这关闭了最后一个有效捕获屏幕的私有API。ReplayKit是唯一的替代方案,但不允许编程访问实际视频数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接