作者:FloatingGuy 转载请注明出处:https://floatingguy.github.io/
作者:FloatingGuy 转载请注明出处:https://floatingguy.github.io/
《深入解析MAC OS X & iOS 操作系统》- 第 十八 章: 内核扩展模块
kext 基本信息 kext 的属性:
所有者 uid 必须是 root, gid必须是 wheel
文件权限不得超过 644
目录权限不得超过 755
预链接:
特殊的 kext 介绍 书中介绍了一个 用来解密的二进制文件的 kext - Dont Steal Mac OS X.kext (DSMOS). 苹果系统于苹果机器EFI模块之间的通信加解密。 iOS上的 IOTextEncryptionFamily 用来代替 DSMOS。
在网上收集 到一些特殊的 kext。
System.kext 最基础的核心系统驱动,mach核心最先载入的驱动,负责于其他扩展通信,
kext 基本结构
文件/目录
内容
MacOS
保存二进制文件
PlugIns
存放相关的 kext
Info.plist
。。
上面几个文件是 bundle 中必备的,其他还有一些文件。
从kernelcache 提取 kext OSX 中 kernelcache提供了完整的内核(包括内核+kext+驱动),预加载必要的驱动,加快启动速度。 iOS 中 kernelcache只包含要加载的 kext(不包含内核)。
OSX & iOS kernelcache 实现对比
操作系统
/System/Library/Caches/*
内容
OSX
com.apple.kext.caches/Startup
胖二进制格式,offset==384处是 complzss
iOS
com.apple.kernelcaches/kernelcache
IMG3 加密 的 kernelcache,采用 complzss压缩
OSX kernelcache 动态创建,iOS是固定的并且根据机型 定制。
6.5.2节 给出了OSX与iOS提取kernelcache 的方法。
作者提供了一个工具joker-dec: Decompress kernelcache to /tmp/kernel (complzss only at this stage) 集合了decache shell 脚本
可以用来查看 iOS中的 kext 列表,前提是要先解压、解密kernelcache。(在10.12 上测试了下,貌似工具有 bug)
胖文件头 签名:0xcafebabe Mach-O签名:0xfeedface(32位)或0xfeedfacf(64位)
从 kernelcache 中提取各个 kext 的步骤:
根据偏移找到解压标记位,解压(ios需要解密)
otool提取 __PRELINK_TEXT 段 (此段加载了 所有的内核扩展) 上面提取的是 kext bundle 列表, 每个 bundle 是 Mach-o Bundle, 通过签名(0xfeedfacf)识别。
kernelcache 对应的属性列表 plist 包含在 PRELINK_INFO 段中。使用 jtool(segedit)提取。kernelcache的plist是ASCII 格式的文本,其中包含了所有 bundle 的 info.plist。
完成提取
插播一句:github上有个项目–machkextdump是dump Kext information 从Macos/iOS系统中,主要是帮助逆向分析用的。
表 18-7 kernelcache plist 文件属性
OSX 提取 kernelcache 实验
这一步该解压了,但是在10.12 上没有 complzss解压工具(需要自己从源码编译),并且发现压缩签名变成了”complzvn”,需要去查看下10.12 的 xnu 代码。
从作者的截图中知道,第一步完成以后是一个 Mach-O的可执行文件。
multi-kext multi-kext (简称 mkext)是不同于 kernelcache的另一种 预链接形式,mkext不包含内核。
mkext 的签名是”MKXTMOSX”。 mkext 头部结构:1
2
3
4
5
6
7
8
uint32_t magic; \ MKXT
uint32_t signature; \ MOSX
uint32_t length; \ mkext 文件大小
uint32_t adler32; \ 从 version 到文件尾的校验值
uint32_t version; \
uint32_t numkexts; \ kext的数量
cpu_type_t cputype; \ CPU_TYPE_ANY
cpu_subtype_t cpusubtype; CPU_SUBTYPE_MULTIPLE
在后文分析kext_request 源代码时,就是针对 mkext 格式分析其 load等具体操作流程。
Kext 开发 在我的 《OSX FirstExtension 开发》 这篇文章中介绍了,如何开发Kext 代码和遇到的问题。
Kext 的内核支持 kext 是在内核态链接。内核态内存默认是 联动内存?? ,消耗物理内存。 (不明白 啥叫联动内存)
kext 是 XNU 独立组件,相对 Mach 和 BSD 都是独立的。管理 kext 部分的代码在 XNU 中是采用 C++ 开发,并且 I/O Kit也是基于 kext 构建。
kmod 支持(已废弃) 我们上面 提到了 Mach 和 Kext 是独立的,这个说法是有点问题。因为 Mach 是 XNU 的核心,kext 只是xnu 的一部分,所以 Mach 必然要将 kext 也加入它的理念中(《XNU内核设计–Mach-IPC原理》文章介绍了 Mach的理念)。
Mach的一般做法就是给 内核组件定义 对象, 然后定义一些管理的API。
Mach 给 kext 定义了 kmod_info
结构体,在osfmk/kern/kmod.h
。
在老版本 XNU 代码中 osfmk/kern/kmod.c
中包含大量 kmod 处理代码,包括 kmod_create、kmod_destroy
等。目前在10.12 代码中这些函数包括kmod_get_info()
都只返回一个 KERN_NOT_SUPPORTED。
libkern 支持 kext 虽然 kmod 框架已经废弃(文件还在 xnu 中)并且定义的 API 都废弃了。 但是 mach 中定义的 kmod_info_t 结构体还沿用至今。目前XNU 管理 kext的代码已经转移到libkern目录下, 并用 C++ 重写对 kext 的支持,相关代码在libkern/c++/OSKext.cpp 中
kmod_info_t 是每一个 kext 在入口点接受的一个参数。创建 kext 时, xcode 会通过 KMOD_EXPLICIT_DECL 宏为这个 kext 初始化一个 kmode_info_t数据,保存在/Xcode/DerivedData/<moduleNmae>_info.c 文件中
然而 并不知道 这个 kmod_info 在新的 libkern框架中有什么用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
typedef struct kmod_info {
struct kmod_info * next ;
int32_t info_version;
uint32_t id;
char name[KMOD_MAX_NAME];
char version[KMOD_MAX_NAME];
int32_t reference_count;
kmod_reference_t * reference_list;
vm_address_t address;
vm_size_t size;
vm_size_t hdr_size;
kmod_start_func_t * start;
kmod_stop_func_t * stop;
} kmod_info_t ;
#define KMOD_DECL(name, version) \
static kmod_start_func_t name ## _module_start; \
static kmod_stop_func_t name ## _module_stop; \
kmod_info_t KMOD_INFO_NAME = { 0 , KMOD_INFO_VERSION, -1U , \
{ #name }, { version }, -1 , 0 , 0 , 0 , 0 , \
name ## _module_start, \
name ## _module_stop };
#define KMOD_EXPLICIT_DECL(name, version, start, stop) \
kmod_info_t KMOD_INFO_NAME = { 0 , KMOD_INFO_VERSION, -1U , \
{ #name }, { version }, -1 , 0 , 0 , 0 , 0 , \
start, stop };
看下xcode 给 FirstExtension.kext 生成 kmod_info 结构体的代码。/Users/xxx/Library/Developer/Xcode/DerivedData/FirstExtension-caeeqdglmmdwxqajtyioipnqbieo/Build/Intermediates/FirstExtension.build/Release/FirstExtension.build/DerivedSources/FirstExtension_info.c
1
2
3
4
5
6
7
8
9
10
11
12
#include <mach/mach_types.h>
extern kern_return_t _start(kmod_info_t *ki, void *data);
extern kern_return_t _stop(kmod_info_t *ki, void *data);
__private_extern__ kern_return_t FirstExtension_start (kmod_info_t *ki, void *data) ;
__private_extern__ kern_return_t FirstExtension_stop (kmod_info_t *ki, void *data) ;
__attribute__((visibility("default" ))) KMOD_EXPLICIT_DECL(com.xxx.FirstExtension, "1.0.0d1" , _start, _stop)
__private_extern__ kmod_start_func_t *_realmain = FirstExtension_start;
__private_extern__ kmod_stop_func_t *_antimain = FirstExtension_stop;
__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;
就是用来注册 kext 的入口函数和出口函数到 kmod_info 结构体中。
kextd 守护进程:该进程是 内核态和用户态的桥梁,辅助完成 kext 的加载和依赖性解析。 kexd 被 launchd 加载时注册了 主机特殊端口 host port #15(HOST_KEXTD_PORT)。 kexd 和用户态进程(客户端)通过 mach 消息通信MIG 子系统 70000 。 iOS 没有 kextd。
IOKit 框架提供了一套 API 封装了和 texd 交互的消息发送和接受。 还有一些 API 给 kextd使用,用来和内核直接交互。 IOKit 框架API, 表18-8.
OSKextLoad
OSKextLoadWithOptions
OSKextUnload
OSKextStart
OSKextStop
OSKextIsStarted
OSKextCopyLoadedKextInfo
上述的 API 都是用户态的。
kext 加载的原理 害怕在代码中迷路的同学,先来 看下流程图吧。
上面提到 kext 的加载机制使用了 Mach 消息,所有的 kext 操作都封装为序列化的 XML 格式,并放在 Mach kext_request 消息的 ool_descriptors 数据中。 下面分析 内核中kext_request 函数如何处理 kext 加载。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
kern_return_t kext_request(
host_priv_t hostPriv,
uint32_t clientLogSpec,
vm_offset_t requestIn,
mach_msg_type_number_t requestLengthIn,
vm_offset_t * responseOut,
mach_msg_type_number_t * responseLengthOut,
vm_offset_t * logDataOut,
mach_msg_type_number_t * logDataLengthOut,
kern_return_t * op_result)
{
result = vm_map_copyout(kernel_map, &map_addr, (vm_map_copy_t )requestIn);
..
request = CAST_DOWN(char *, map_addr);
if (requestLengthIn > sizeof (mkext2_header)) {
mkextHeader = (mkext2_header *)request;
if (MKEXT_GET_MAGIC(mkextHeader) == MKEXT_MAGIC &&
MKEXT_GET_SIGNATURE(mkextHeader) == MKEXT_SIGN) {
isMkext = true ;
}
}
if (isMkext) {
...
*op_result = OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec,
request, requestLengthIn,
&logData, &logDataLength);
#endif
} else
{
*op_result = OSKext::handleRequest(hostPriv,
(OSKextLogSpec)clientLogSpec,
request, requestLengthIn,
&response, &responseLength,
&logData, &logDataLength);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
OSReturn
OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec,
request, requestLengthIn,
&logData, &logDataLength) {
...
mkextData = OSData::withBytesNoCopy(mkextBuffer,
mkextBufferLength);
...
result = readMkext2Archive(mkextData, &mkextPlist, NULL );
...
predicate = _OSKextGetRequestPredicate(mkextPlist);
if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
OSKextLog( NULL ,
kOSKextLogErrorLevel |
kOSKextLogLoadFlag,
"Received kext load request with no predicate; skipping." );
result = kOSKextReturnInvalidArgument;
goto finish;
}
requestArgs = OSDynamicCast(OSDictionary,
mkextPlist->getObject(kKextRequestArgumentsKey));
...
kextIdentifier = OSDynamicCast(OSString,
requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
...
result = OSKext::loadKextWithIdentifier(
kextIdentifier,
false ,
delayAutounload,
startKextExcludeLevel,
startMatchingExcludeLevel,
personalityNames);
...
return result;
}
下表是kext_request 支持的命令,这些命令保存在Kext Request Predicate
键值中。
1
2
3
4
5
6
7
8
9
10
11
12
13
mkext2_header 成员
uint32_t magic; \
uint32_t signature; \
uint32_t length; \
uint32_t adler32; \
uint32_t version; \
uint32_t numkexts; \
cpu_type_t cputype; \
cpu_subtype_t cpusubtype;
uint32_t plist_offset;
uint32_t plist_compressed_size;
uint32_t plist_full_size;
从kext 中提取info.plist1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
OSReturn
OSKext::readMkext2Archive(
OSData * mkextData,
OSDictionary ** mkextPlistOut,
uint32_t * checksumPtr) {
mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
mkextPlistCompressedSize;
...
mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
if (mkextPlistCompressedSize) {
...
} else {
mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
}
parsedXML = OSUnserializeXML(mkextPlistDataBuffer, &errorString);
if (parsedXML) {
mkextPlist = OSDynamicCast(OSDictionary, parsedXML);
}
if (!mkextPlist) {
...
goto finish;
}
if (mkextPlistOut) {
*mkextPlistOut = mkextPlist;
(*mkextPlistOut)->retain();
}
mkextInfoDictArray = OSDynamicCast(OSArray,
mkextPlist->getObject(kMKEXTInfoDictionariesKey));
...
goto finish;
}
count = mkextInfoDictArray->getCount();
for (i = 0 ; i < count; i++) {
OSDictionary * infoDict;
infoDict = OSDynamicCast(OSDictionary,
mkextInfoDictArray->getObject(i));
...
if (infoDict) {
OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
OSSafeReleaseNULL(newKext);
}
}
result = kOSReturnSuccess;
finish:
OSSafeReleaseNULL(parsedXML);
OSSafeReleaseNULL(mkextPlistUncompressedData);
OSSafeReleaseNULL(errorString);
return result;
}
load kext 的代码, 这个函数有个重载函数 通过第一个参数可以区分。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
OSReturn
OSKext::loadKextWithIdentifier(
OSString * kextIdentifier,
Boolean allowDeferFlag,
Boolean delayAutounloadFlag,
OSKextExcludeLevel startOpt,
OSKextExcludeLevel startMatchingOpt,
OSArray * personalityNames)
{
OSReturn result = kOSReturnError;
OSReturn pingResult = kOSReturnError;
OSKext * theKext = NULL ;
OSDictionary * loadRequest = NULL ;
const OSSymbol * kextIdentifierSymbol = NULL ;
IORecursiveLockLock(sKextLock);
OSKext::recordIdentifierRequest(kextIdentifier);
theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
if (!theKext) {
if (!allowDeferFlag) {
...
goto finish;
}
if (!sKernelRequestsEnabled) {
...
goto finish;
}
kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
&loadRequest);
if (result != kOSReturnSuccess) {
goto finish;
}
if (!_OSKextSetRequestArgument(loadRequest,
kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
result = kOSKextReturnNoMemory;
goto finish;
}
if (!sKernelRequests->setObject(loadRequest)) {
result = kOSKextReturnNoMemory;
goto finish;
}
if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol)) {
result = kOSKextReturnNoMemory;
goto finish;
}
}
pingResult = OSKext::pingKextd();
if (pingResult == kOSKextReturnDisabled) {
...
}
result = kOSKextReturnDeferred;
goto finish;
}
result = theKext->load(startOpt, startMatchingOpt, personalityNames);
if (result != kOSReturnSuccess) {
...
OSKext::removeKext(theKext,
true );
goto finish;
}
...
finish:
OSSafeReleaseNULL(loadRequest);
OSSafeReleaseNULL(kextIdentifierSymbol);
IORecursiveLockUnlock(sKextLock);
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
#define kMKEXTInfoDictionariesKey "_MKEXTInfoDictionaries"
#define kMKEXTBundlePathKey "_MKEXTBundlePath"
#define kMKEXTExecutableRelativePathKey "_MKEXTExecutableRelativePath"
#define kMKEXTExecutableKey "_MKEXTExecutable"
#define kMKEXTLoadRequestKey "_MKEXTLoadRequest"
#define kMKEXTLoadRequestLoadKey "Load Kext"
#define kMKEXTLoadRequestStartKey "Start Kext"
#define kMKEXTLoadRequestAddPersonalitiesKey "Add Personalities"
#define kMKEXTLoadRequestDisableAutounloadKey "Disable Autounload"
#define kKextRequestPredicateLoad "Load"
总结一番:
kext_request 的参数 requestIn的类型
当 kextd 发出 load请求时, 向kext_request 发送一个 mkext文件
当 kextd 发出start/stop/…其他请求时,向kext_request 发送一个 XML文件
mkext Load
需要2个过程,L1 阶段是从 mkext 中获取 Plist 以后就创建 OSKext 对象,并保存在 sKextsByID 字典中。L2 阶段从sKextsByID 中取出 OSKext,并调用 OSKext->load
方法
OSKext::initialize
中给 kernel 创建 OSKext, 并初始化kext 全局管理对象(sKextsByID, g_kernel_kmod_info, sLoadedKexts 等
)
当kext_request 发送 Start
时, 最终调用到OSKext::start
函数内, 会将控制权交给 kext的 xxx_start方法
3/4 条会在下一篇中 给出代码分析。
调试 kext_request 这里调试的是 libsystem_kernel.dylib 中的kext_request 代码通过 mach msg 发送消息给上一节分析的是 xnu 内核中的 kext_request 代码。1
2
第一次请求
0x7fe4e2805400: "<dict><key>Kext Request Predicate</key><string>Get Loaded Kext Info</string><key>Kext Request Arguments</key><dict><key>Kext Request Info Keys</key><array><string>CFBundleIdentifier</string><string>CFBundleVersion</string><string>OSBundleCompatibleVersion</string><string>OSBundleIsInterface</string><string>OSKernelResource</string><string>OSBundleCPUType</string><string>OSBundleCPUSubtype</string><string>OSBundlePath</string><string>OSBundleUUID</string><string>OSBundleStarted</string><string>OSBundleLoadTag</string><string>OSBundleLoadAddress</string><string>OSBundleLoadSize</string><string>OSBundleWiredSize</string><string>OSBundlePrelinked</string><string>OSBundleDependencies</string><string>OSBundleRetainCount</string></array><key>CFBundleIdentifier</key><array><string>com.apple.driver.KextExcludeList</string></array></dict></dict>"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
第三次
<dict>
<key>Kext Request Predicate</key>
<string>Load</string>
<key>Kext Request Arguments</key>
<dict>
<key>Start Exclude Level</key>
<integer ID="0" size="8">0x0</integer>
<key>Start Matching Exclude Level</key>
<integer IDREF="0" />
<key>CFBundleIdentifier</key>
<string ID="1">com.apple.filesystems.ntfs</string>
</dict>
<key>_MKEXTInfoDictionaries</key>
<array>
<dict>
<key>CFBundleName</key>
<string>NTFS File System Extension</string>
<key>DTXcode</key>
<string>0720</string>
<key>DTSDKName</key>
<string>macosx10.11internal</string>
<key>DTSDKBuild</key>
<string>15C45</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleVersion</key>
<string ID="2">3.13</string>
<key>BuildMachineOSBuild</key>
<string>15A284</string>
<key>_MKEXTExecutableRelativePath</key>
<string>Contents/MacOS/ntfs</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string IDREF="2" />
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleInfoDictionaryVersion</key>
</dict>
</array>
</dict>
kext 相关工具 第三方工具
命令
用途
jtool
分析 Mach-O格式
joker
(不能用)
联动内核? 直接使用物理内存
常用命令
命令
用途
kextd
用户空动态加载kext 的守护进程,被 launchd 启动
kextfind
通过属性 和 标准查询 kext
kextlibs
解析 kext的依赖
kextload
kext 加载器
kextunload
kext 卸载器
kextutil
检查 kext 的 bug, 等功能
kextstat
查看已经安装的 kext
————–
————–
ioreg
show I/O Kit registry,”man ioreg”
ioclasscount
内核对象的内存管理是基于引用计数,该工具可以用来打印所有已加载的内核对象的引用计数个数,便于调试内存泄露
sudo zprint
查看 kalloc 分配的內存域 (类似于 slab 缓存)
Console
查看 system.log
IORegistryExplorer
查看 kext IOLog 輸出信息
USB Prober
查看 usb 使用情況
————–
————–
mkextunpack
解包 mkext
kextcache
kextstat kextstat 查看系统(/System/Library/Extensions下的 kext 不一定全部加载了)当前加载的 kext。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
blog git:(master) ✗ kextstat
Index Refs Address Size Wired Name (Version) UUID <Linked Against>
1 94 0xffffff7f80a46000 0x9d30 0x9d30 com.apple.kpi.bsd (16.4.0) 548007FE-B217-4499-8640-238BC24F4A17
2 8 0xffffff7f80e59000 0x3940 0x3940 com.apple.kpi.dsep (16.4.0) 38FEF282-1288-42F3-8E55-EDD04053B20B
3 119 0xffffff7f80a04000 0x21040 0x21040 com.apple.kpi.iokit (16.4.0) EA3A39EE-499F-44C3-88F2-334FEB308226
4 126 0xffffff7f80a26000 0xd200 0xd200 com.apple.kpi.libkern (16.4.0) 677B5452-B294-43D3-A562-F13502C04C54
5 114 0xffffff7f80a00000 0x3dd0 0x3dd0 com.apple.kpi.mach (16.4.0) 2A128386-C535-4026-B9D7-E91D3360CEF4
6 62 0xffffff7f80a34000 0xba10 0xba10 com.apple.kpi.private (16.4.0) F8C31C2F-2831-4680-90DF-97A2EA6DE9F0
7 76 0xffffff7f80a40000 0x5890 0x5890 com.apple.kpi.unsupported (16.4.0) C8C39C9E-83FE-4274-BA90-9535845EFF9C
8 7 0xffffff7f80e60000 0xa9000 0xa9000 com.apple.kec.corecrypto (1.0) 25C67059-A2B6-328F-BCCF-F81CC7FFC10F <7 6 5 4 3 1>
9 0 0xffffff7f80fbb000 0xf000 0xf000 com.apple.kec.pthread (1) 479F2E9E-1F15-3D76-A407-DB04C1277527 <7 6 5 4 1>
10 1 0xffffff7f80ff1000 0xb000 0xb000 com.apple.kec.Libm (1) 51D82C5F-0248-334D-ADC6-5861BBB83C97 <4>
11 27 0xffffff7f80ffc000 0x9000 0x9000 com.apple.iokit.IOACPIFamily (1.4) 4F7FB6AD-2498-3F71-827C-ED7AA4BF2511 <7 6 4 3>
12 30 0xffffff7f80b32000 0x34000 0x34000 com.apple.iokit.IOPCIFamily (2.9) 57960DC6-4099-31BC-9B47-52CD647779C7 <7 6 5 4 3>
13 2 0xffffff7f831d7000 0x60000 0x60000 com.apple.driver.AppleACPIPlatform (5.0) 867C81BE-EA01-3A65-89F4-06D78E6514CA <12 11 7 6 5 4 3 1>
14 1 0xffffff7f812ae000 0xb000 0xb000 com.apple.driver.AppleFDEKeyStore (28.30) EA5D0966-E8EA-337A-98EB-195806E8F723 <8 7 6 5 4 3 1>
15 4 0xffffff7f816a9000 0x7000 0x7000 com.apple.iokit.IOReportFamily (31) B14DC3D3-7250-3DA3-BF50-C666EBEDAF4C <5 4 3>
16 7 0xffffff7f80a50000 0x27000 0x27000 com.apple.iokit.IOStorageFamily (2.1) 3238C6A2-A948-378E-9C53-3883089C1B52 <7 6 5 4 3 1>
17 0 0xffffff7f81779000 0x190
第1列 Index是 kext 在表中的索引 第2列 Refs 显示当前 kext 依赖的 kext 的个数,每一项末尾尖括号<>内是依赖的 kext 的index。
从依赖关系树状图可以看出,树根部是1-7这7个 kext(kpi.*)
zprint 1
2
3
4
5
6
7
8
9
10
sh-3.2# zprint | grep port
elem cur max cur max cur alloc alloc
zone name size size size #elts #elts inuse size count
ipc.ports 336 2072K 24924K 6314 75958 5779 4K 12 C
ipc.port.sets 88 40K 1868K 465 21736 388 8K 93 C
ipc.task.importance 168 24K 4032K 146 24576 106 12K 73 C
ipc.importance.inherit 88 8K 2112K 93 24576 2 8K 93 C
com.apple.iokit.IOReportFamily
Change Log
Time
Change
2017-03-17
kext_request Load源代码分析
2017-03-20
梳理文章, 下一篇专门分析 OSKext 中的几个函数 load, start,withMkext2Info…