我一直想知道是否可以编写内核扩展来充当另一个内核扩展的UserClient。通常,我们在用户端使用IOConnect
来访问内核扩展上的IOUserClient
方法。但是在Kernel.framework中没有这样的方法(我完全理解它的意图是以这种方式使用)。但我只是想知道上述情况是否可行。
首先,当您在用户空间中调用IOServiceOpen()
时,会在传入其句柄的服务上调用IOService::newUserClient()
。作为结果创建类的对象取决于服务是否以及如何覆盖该方法。
主要有两种可能性,它们可以决定如何覆盖默认行为。
newUserClient
,或者它在某些情况下调用IOService::newUserClient()
默认实现(例如,如果它不知道传入的type
),则用户客户端类由服务上的IOUserClient
属性确定。newUserClient()
,则用户客户端类通常是硬编码的,否则将遵循一些特定于kext的逻辑。要在使用IOUserClient
属性(1)时覆盖用户客户端类:
IOKitPersonality
的副本。
在你的版本中增加IOProbeScore
(或添加非零IOProbeScore
,如果没有),所以你的个性优先于原来的kext。
将IOUserClient
属性设置为要使用的用户客户端类。
我对此并不是100%肯定,但我认为你需要将个性的CFBundleIdentifier
更改为你的kext,并在OSBundleLibraries
下列出另一个kext。如果这不起作用,请尝试使用原始包标识符。
如果原始kext的Info.plist具有OSBundleReqired
键的值,请确保将其复制到您的值,具有相同的值。如果服务专门包含防止其不知道的用户客户端的代码,则仍然无法工作。
注意:包括OSBundleLibraries
中的原始kext仅在原始kext的Info.plist包含OSBundleCompatibleVersion
值时才有效。如果没有,你就不能把它添加到你的OSBundleLibraries
,但你仍然可以使它工作 - 例如,如果你只是在旧的kext上调用virtual
成员函数。
注意2:当然,这将完全覆盖旧的用户客户端类。创建用户客户端连接的任何进程都将获得您的客户端,而不是原始客户端。这可能会干扰沙盒应用。
注意3:您可能需要添加一个虚拟的IOResources
绑定服务,以便在没有用户客户端的情况下加载kext,因为如果没有任何类的实例没有活动,通常会卸载kexts。
要通过覆盖newUserClient()
函数来覆盖用户客户端类(2):
这与上面的工作方式类似,但实际上您是子类的原始服务类并直接覆盖newUserClient
。这允许您添加用户客户端(例如,用于不同的type
值),而不是替换唯一的现有客户端。您将再次需要用更高分的实现替换原始的IOKitPersonality,但这次您还将IOClass
更改为您的类。
这一个的一些进一步限制:
OSBundleCompatibleVersion
,否则你将无法链接它 - 这需要上传到它的构造函数,填写你的子类的vtable等。我可能不需要指出这一点但是:在执行此操作时通常要格外小心,特别是在覆盖系统关键字时,如果出错,可能会导致操作系统出现故障。我只会做这样的事情作为最后的手段,如果我最终想要做的事情是不可能的任何其他方式。