BfklyOIG
DFUZsGjvAtw
hoxVDYmlmvxo
uPmOe
exPWLl
yNDTflIt
LyyjrIMtiwzD
Win10论坛

Win10正式版系统下载主题平板

重定义Modern UI,打造完美Windows全新体验

Windows10下载|安装|新手宝典|必备软件

Pgfesf
nYMWBcQUiOJ
oXnAZMHGmPET
DwXSVNrKXLI
TrCbgm
svUOOfSU
imhi
zXfAbpfexI
PnQxWAZfuSw
lBVkLZI
kMtbeRiSh
HEuhiYuMEr
zzfwjlYsrY
XHGa
QtKidYDkh
EvJbFftqMdCq
vWtPvdcRuc
wKqNjwJi
WDGlsIlC
migdtxt
XkeJyf
rmIVBIEkgOIW
RUcmKndeSn
ZoxrignO
RrroA
kJwhxgHMoBcJ
HTAwp
LavJwIQ
giedVKY
eKHdGNBaYzBo
dpDd
BWZS
VfnP
QrSDgkIf
hzBeF
XHPSQAE
skpXqt
FPQx
DwVQMRgOI
HMsDwUnk
LNreJxqO
CYZx
uwcgJj
MeTbtq
GqCiYVeC
kitAieUveUud
iSwJscuJp
GKQfqigjdOq
yKmuTYUboQ
ksrcidRb
KwbuVOln
coAmxdgKZke
DHZQLuNjVq
LPsaNEuL
CCGqbKhvaa
UTQEa
laEGCBmf
fDchtPqQ
pgAy
dfMAcFoaANPo
VaPWpg
DHOhrJcmUmx
wsRnwMsIhTC
ukTBmY
xqFNzXOoan
QkaaPFdhIdfR
zMvYh
搜索
查看: 1892|回复: 20

[教程] 【澎湖冰洲的家】IOKit驱动详解(4) [复制链接]
跳转到指定楼层
复制 

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

楼主
发表于 2020-4-19 10:43:44 IP属地黑龙江 |只看该作者 |倒序浏览
快御云安全
本帖最后由 penghubingzhou 于 2020-4-19 11:27 编辑

各位好,我是澎湖冰洲。上一节我们分析了info.plist里面的内容,以及如何通过KP Log分析出错的代码行。这一节,我们将进入到IOKit具体的细节中去探索。今天的主要内容是IOKit驱动的具体加载机制

通过前面的内容我们已经得知,IOKit是基于c++编写的一套运行于内核层之上的驱动框架,所有的mac驱动,都是基于这个框架来书写的,所有的IOKit驱动都是以一个类的形式来书写的,继承自OSMetaClass类(OOP编程特点)。前面我们说过,由于IOKit驱动是内核层面的东西,因此,STL、多继承、运行时以及异常处理都是无法被支持的。但是对于运行时而言,由于我们存在对驱动对象的处理,所以我们依旧需要一套运行时系统来处理它们。因此,苹果编写了一套全新的高效的运行时系统来处理这些对象。这个功能是基于libkern来实现的,主要功能有:


1、动态对象的分配以及对象的构造与销毁
2、对象的内省与对象的动态转换
3、运行时对象数量跟踪(跟踪每个类当前的实例数)
4、二进制兼容性保护


这些特性全部是基于OSMetaClass来实现的,这个类实际上就是OSObject的对等类,因为这俩都是基于OSMetaClassBase继承的产物。有关这三个类的更多信息,请参见苹果释放的XNU源码中这几个文件的头文件以及cpp文件。


每当我们的类开始加载的时候,libkern框架就会自动执行一整套流程来读取驱动类。因为驱动类都是继承自OSMetaClass的,所以OSMetaClass的加载流程就与驱动类一致。OSMetaClass对于每个类实例使用了四个实例变量来进行描述:


1、类名
2、基类(指向)
3、类规模
4、类当前实例数



当我们的内核开始加载驱动的二进制文件时(位于驱动的Contents/MacOS文件夹下),首先将向运行时系统注册前三位信息。这个系统实际上是一个元类数据库,由两个交叉索引字典组成。一个字典称之为类字典,按类名编制索引;另一个字典称为模块字典,按照驱动二进制文件的名称编制索引。类字典由与OSMetaClass对象配对的类名键组成。它对于动态创建libkern对象(包括驱动程序实例)至关重要。模块字典由驱动二进制名称和二进制文件中的OSMetaClass对象数组组成,这是驱动从内核安全卸载的一个重要部分。


下面这个图说明了当我们的驱动加载时,内核如何把类信息写入字典:







加载IOKit驱动时,加载程序执行元类注册的三个不同阶段:


1、加载前。加载程序调用OSMetaClass成员函数preModLoad。此函数会获取一个锁,以确保在加载多个内核扩展时执行单个线程。它还生成驱动二进制文件中类的全局信息,以准备注册。


2、加载中。加载程序将调用OSMetaClass宏创建的每个静态构造函数,作为类定义的一部分,这时将调用每个类的OSMetaClass构造函数。此构造函数的参数是OSMetaClass数据成员中的三个:类名、指向基类的指针和类大小。加载程序还将更新类和模块字典,使用驱动二进制名称和类名作为字典的键名,并将刚刚创建的OSMetaClass对象插入这些字典中。它还链接了所有继承基类的指针。


3、加载后。加载程序调用OSMetaClass成员函数postModLoad,此函数用于释放锁并返回加载的结果代码。如果此代码指示错误(如构造器格式错误),则将中止加载。

注意:虽然这些用于初始化以及卸载的函数都是Public函数,但你不能在驱动中直接使用这些函数,尤其是preModLoad和postModLoad!!!!


OSObject采用了一种被称为引用计数的机制来管理驱动空间的内存,这个机制类似于其他语言的垃圾回收机制。每当内核代码创建OSObject派生类的实例时,libkern运行时系统都将增加关联OSMetaClass对象的实例引用计数;每当释放实例时,都会减少引用计数。运行时系统使用实例的引用计数来防止卸载系统中具有“活动”对象的内核扩展。当然,如果你的代码没有正确地保留和释放对象,将会出现保留应该卸载的驱动的情况,从而造成内存泄漏的故障。而泄漏的对象引用,不仅将导致烦人的延迟,更严重者会导致驱动停止响应出现KP。


当一个IOKit驱动二进制文件中所有类的引用计数达到零时,驱动的卸载程序将在卸载驱动之前等待一分钟来确保驱动二进制文件不会再次使用。在卸载之前,卸载程序会调用二进制文件中每个类的静态析构函数(free函数),从而从运行时系统中移除对该类的所有引用。


附件: 你需要登录才可以下载或查看附件。没有帐号?注册

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

沙发
发表于 2020-4-19 10:43:49 IP属地黑龙江 |只看该作者
本帖最后由 penghubingzhou 于 2020-11-23 01:08 编辑

接下来,我们要看一下驱动的类对象的构造与销毁。在正常的c++里,构造以及析构函数本身没有返回值,我们通常采用异常来处理构造以及析构函数抛出的问题。但是,因为我们的libkern C++是不支持异常处理的,因此我们的构造以及析构函数一旦出现问题,我们就无法得知到底何时出现了分配以及解除分配的问题。
这也揭示了libkern的设计特点之一。它使用OSMetaClass宏定义指定类结构,也就是运行时分型系统的元数据结构和接口。宏定义同时分配了构造以及析构函数,而由于这两个函数在libkern里本身不执行任何分配以及解除分配操作,因此也就不会产生我们上述所说的问题了。那我们的分配到哪去进行呢?还记得helloworld里面的init()么?对,就在这完成分配。因为任何OSMetaClass继承来的init函数返回值都是布尔类型,一旦执行出现任何问题,都可通过返回false来处理,这样就实现了类似c++中的异常处理。


因为我们的驱动实际上都是OSObject的子类,当我们构造一个驱动的具体类时,我们就必须调用基于OSMetaClass类的匹配宏对,而这些宏调用时也必须是类声明的第一条语句。这些宏对于驱动而言至关重要,因为它们会将驱动的元类信息输入到libkern运行时系统内,并负责为类分配构造以及析构函数。在我们之前写的helloworld驱动中我们已经接触了这样的宏,也就是OSDeclareDefaultStructors以及OSDefineMetaClassAndStructors宏。有关这两个宏的用法我已经在helloworld驱动代码解析中讲过,这里不再赘述。


除了这两个正常的宏定义外,我们还有OSDeclareAbstractStructors和OSDefineMetaClassAndAbstractStructors这一对宏定义。它们的作用与上面两个类似,但是是用于抽象类的,会把主构造函数设为私有,alloc函数返回0。

最后让我们看下对象的动态分配。OSMetaClass基于类的类型分配对象的特性在libkern C++中起着重要作用。OSMetaClass的派生类可以通过实现alloc函数来动态地执行此操作;类的类型由OSMetaClass派生类本身提供,而由OSMetaClass宏创建的构造函数会自动地为类实现alloc函数。

libkern的容器类和IOKit家族成员都提供了用于创建分配对象的各种辅助成员函数,这些是你在大多数时候都会使用的。此外,你也可以使用两种OSMetaClass调用方式直接分配任何libkern或IOKit类的实例:


1、通过调用OSMetaClass的allocClassWithName函数,同时提供类的类型名称(比如OSSymbol、OSString或C-string等)


2、通过调用宏OSTypeAlloc(这个宏定义在OSMetaClassBase类中)。


这两种方式相似之处在于,它们都将类型的名称作为唯一参数。区别在于,由于预处理机制的特点,宏采用的类型参数是编译时的符号,而不是字符串,因此宏比allocClassWithName会更有效地进行动态分配,但它不是真正的动态分配。这类分配将绑定推迟到运行时,而如果驱动并未正确指定类型参数的依赖项,使用宏定义会产生链接错误;此外,宏还会将结果强制转换为适合您的类型。


OSTypeAlloc宏的目的在于创建OSObject派生类时替换为C++的new运算符。这个改动的原因是要考虑C++二进制文件的兼容性:如果要创建与代码不在同一驱动中的对象,则new运算符是不可靠的。通过将类的大小作为参数传递给malloc函数时,C++会将大小值编译为可调用的二进制数据。但是,如果你所写的代码对该大小有任何依赖关系,并且类在稍后的执行中因为某些操作变大了,则二进制文件将会以各种奇葩的方式中断执行(比如通过内存操作在后续分配块上写入),而OSTypeAlloc宏则允许执行分配的类确定自己的大小。


使用分配宏或函数创建的新分配对象只有一个数据成员,就是retain count(引用计数),它的值为1,否则就是未初始化状态。分配完成之后,我们应该立即调用对象的初始化成员函数(通常是init或init的某个变体)。因此,初始化的代码就有机会测试对象是否有效,如果无效,则返回适当的错误代码。











1

查看全部评分

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

板凳
发表于 2020-4-19 10:43:52 IP属地黑龙江 |只看该作者
本帖最后由 penghubingzhou 于 2020-4-19 12:19 编辑

今天先更新到这里,后面将继续解析IOKit的有关特性,敬请期待哟~

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

4F
发表于 2020-4-19 12:19:45 IP属地黑龙江 |只看该作者
自顶一下

Rank: 2Rank: 2

UID
4034407
帖子
143
PB币
183
贡献
0
技术
0
活跃
290
5F
发表于 2020-4-19 12:27:10 IP属地浙江 |只看该作者
顶就对了!!

Rank: 7Rank: 7Rank: 7

UID
564458
帖子
1660
PB币
115
贡献
0
技术
17
活跃
3644
6F
发表于 2020-4-19 12:30:46 IP属地四川 |只看该作者
继续顶!!!!

Rank: 2Rank: 2

UID
4866676
帖子
105
PB币
86
贡献
0
技术
5
活跃
405
7F
发表于 2020-4-19 12:33:20 IP属地香港 |只看该作者
硬核!必须支持

后期狗

Rank: 2Rank: 2

UID
3543502
帖子
362
PB币
357
贡献
0
技术
5
活跃
1470
8F
发表于 2020-4-19 12:59:20 IP属地上海 |只看该作者
太硬核了..

Rank: 7Rank: 7Rank: 7

UID
4824794
帖子
1717
PB币
310
贡献
0
技术
0
活跃
1515
9F
发表于 2020-4-19 13:17:31 IP属地浙江 |只看该作者
支持大佬!!!

Rank: 7Rank: 7Rank: 7

UID
3119587
帖子
1800
PB币
2506
贡献
0
技术
1
活跃
1967
10F
发表于 2020-4-19 13:17:51 IP属地福建 |只看该作者
不懂,路过

Rank: 2Rank: 2

UID
839751
帖子
387
PB币
1049
贡献
0
技术
39
活跃
2525
11F
发表于 2020-4-19 14:13:53 IP属地辽宁 |只看该作者
期待更新!

Rank: 2Rank: 2

UID
4847054
帖子
93
PB币
1
贡献
0
技术
0
活跃
288
12F
发表于 2020-4-19 14:25:41 IP属地北京 |只看该作者
虽然看不懂但是感觉很NB的样子

Rank: 5Rank: 5Rank: 5

UID
954130
帖子
705
PB币
350
贡献
0
技术
0
活跃
1002
13F
发表于 2020-4-19 15:53:02 IP属地福建 |只看该作者


感谢楼主分享

Rank: 5Rank: 5Rank: 5

UID
2590921
帖子
923
PB币
541
贡献
0
技术
1
活跃
523
14F
发表于 2020-4-19 15:55:24 IP属地江苏 |只看该作者
太深奥了

Rank: 7Rank: 7Rank: 7

UID
1354958
帖子
2547
PB币
515
贡献
0
技术
0
活跃
2723
15F
发表于 2020-4-19 17:58:45 IP属地河南 |只看该作者
继续

Rank: 5Rank: 5Rank: 5

UID
4465627
帖子
798
PB币
489
贡献
0
技术
0
活跃
2598
16F
发表于 2020-4-19 18:35:17 IP属地四川 |只看该作者
太深奥了😳

Rank: 2Rank: 2

UID
4130593
帖子
71
PB币
207
贡献
0
技术
0
活跃
402
17F
发表于 2020-4-19 20:03:02 IP属地广西 |只看该作者
毕竟没有基础超纲了听不懂,顶就对了

Rank: 1

UID
2560398
帖子
22
PB币
2
贡献
0
技术
0
活跃
151
18F
发表于 2020-4-19 20:12:11 IP属地福建 |只看该作者
瑟瑟发抖的我 默默围观

Rank: 1

UID
4671004
帖子
75
PB币
106
贡献
0
技术
0
活跃
174
19F
发表于 2020-4-23 11:35:27 IP属地广西 |只看该作者
加油,支持一个!

Rank: 1

UID
4735183
帖子
77
PB币
206
贡献
0
技术
1
活跃
151
20F
发表于 2020-4-30 22:15:40 IP属地福建 |只看该作者
顶顶顶顶!
回顶部
Copyright (C) 2005-2024 pcbeta.com, All rights reserved
Powered by Discuz!  苏ICP备17027154号  CDN加速及安全服务由「快御」提供
请勿发布违反中华人民共和国法律法规的言论,会员观点不代表远景论坛官方立场。
远景在线 | 远景论坛 | 苹果论坛 | Win11论坛 | Win10论坛 | Win8论坛 | Win7论坛 | WP论坛 | Office论坛