作者: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 的步骤:

  1. 根据偏移找到解压标记位,解压(ios需要解密)
  2. otool提取 __PRELINK_TEXT 段 (此段加载了 所有的内核扩展)
    上面提取的是 kext bundle 列表, 每个 bundle 是 Mach-o Bundle, 通过签名(0xfeedfacf)识别。
  3. kernelcache 对应的属性列表 plist 包含在 PRELINK_INFO 段中。使用 jtool(segedit)提取。kernelcache的plist是ASCII 格式的文本,其中包含了所有 bundle 的 info.plist。
  4. 完成提取

插播一句:github上有个项目–machkextdump是dump Kext information 从Macos/iOS系统中,主要是帮助逆向分析用的。

表 18-7 kernelcache plist 文件属性
kernelcache-plist

OSX 提取 kernelcache 实验

original-osx-kernelcache

thincache.png
这一步该解压了,但是在10.12 上没有 complzss解压工具(需要自己从源码编译),并且发现压缩签名变成了”complzvn”,需要去查看下10.12 的 xnu 代码。

first step
从作者的截图中知道,第一步完成以后是一个 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; // version of this structure
uint32_t id;
char name[KMOD_MAX_NAME];
char version[KMOD_MAX_NAME];
int32_t reference_count; // # linkage refs to this
kmod_reference_t * reference_list; // who this refs (links on)
vm_address_t address; // starting address
vm_size_t size; // total size
vm_size_t hdr_size; // unwired hdr size
kmod_start_func_t * start; // kext 入口
kmod_stop_func_t * stop; // kext 出口
} 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 加载的原理

OSKext::kext_request
害怕在代码中迷路的同学,先来 看下流程图吧。

上面提到 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,
/* in only */ uint32_t clientLogSpec,
/* in only */ vm_offset_t requestIn,
/* in only */ mach_msg_type_number_t requestLengthIn,
/* out only */ vm_offset_t * responseOut,
/* out only */ mach_msg_type_number_t * responseLengthOut,
/* out only */ vm_offset_t * logDataOut,
/* out only */ mach_msg_type_number_t * logDataLengthOut,
/* out only */ 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; //OK
}
}
// 传递一个 mkext 包。
/*
通过分析handleRequest 流程确定,当传入 Load Predicate 时,一定是 mkext 格式的数据,应为还没有加载只有 mkext 文件可以load
*/
if (isMkext) {
...
*op_result = OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec,
request, requestLengthIn,
&logData, &logDataLength); //
#endif /* defined(SECURE_KERNEL) */
} else // 或者传递一个 XML 文件 (略)
{
*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); //
...
// 文本字符串
// 获取 kext 的操作命令:Load
predicate = _OSKextGetRequestPredicate(mkextPlist);
//检查 predicate是否是 “Load”, 这里 只处理 Load Predicate
if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
OSKextLog(/* kext */ NULL,
kOSKextLogErrorLevel |
kOSKextLogLoadFlag,
"Received kext load request with no predicate; skipping.");
result = kOSKextReturnInvalidArgument;
goto finish;
}
// 加载 info.plist 中的参数
requestArgs = OSDynamicCast(OSDictionary,
mkextPlist->getObject(kKextRequestArgumentsKey));
...
// 获取当前 kext 的 Bundle id (唯一标识)
kextIdentifier = OSDynamicCast(OSString,
requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
...
/* Load the kext, with no deferral, since this is a load from outside
* the kernel.
* xxx - Would like a better way to handle the default values for the
* xxx - start/match opt args.
*/
result = OSKext::loadKextWithIdentifier( //[通过Identifier来加载 kext ]
kextIdentifier,
/* allowDefer */ false, //不支持 延迟加载
delayAutounload,
startKextExcludeLevel,
startMatchingExcludeLevel,
personalityNames);
...
return result;
}

下表是kext_request 支持的命令,这些命令保存在Kext Request Predicate键值中。

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.plist

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
OSReturn
OSKext::readMkext2Archive(
OSData * mkextData,
OSDictionary ** mkextPlistOut,
uint32_t * checksumPtr) {
// 获取mkext2_header的 plist_offset、plist_compressed_size、plist_full_size字段。
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);
}
//mkextPlist 是一个字典
if (!mkextPlist) {
...
goto finish;
}
// 上层 传入mkextPlistOut
if (mkextPlistOut) {
*mkextPlistOut = mkextPlist;
(*mkextPlistOut)->retain();
}
//提取 _MKEXTInfoDictionaries key 对应的数据
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));
...
// 这个 创建一个 newKext 对象,然后释放(计数器-1)。但是 系统还保留了 OSKext 在全局对象中
if (infoDict) {
OSKext * newKext = OSKext::withMkext2Info(infoDict, mkextData);
OSSafeReleaseNULL(newKext);
}
}
/* Even if we didn't keep any kexts from the mkext, we may have a load
* request to process, so we are successful (no errors occurred).
* 即使 我们没有 引用任何 kext, 我们还需要给进程发送一请求
*/
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; // do not release
OSDictionary * loadRequest = NULL; // must release
const OSSymbol * kextIdentifierSymbol = NULL; // must release
IORecursiveLockLock(sKextLock);
OSKext::recordIdentifierRequest(kextIdentifier);
theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
if (!theKext) {
if (!allowDeferFlag) {
...
goto finish;
}
if (!sKernelRequestsEnabled) {
...
goto finish;
}
/* Create a new request unless one is already sitting
* in sKernelRequests for this bundle identifier
* 创建一个 kernel 请求,请求去加载 kextIdentifier 对应的 kext
*/
kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol)) {
result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad, //"Kext Load Request"
&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;
}
}
// 查看是否可以 load kext
pingResult = OSKext::pingKextd();
if (pingResult == kOSKextReturnDisabled) {
...
}
result = kOSKextReturnDeferred;
goto finish;
}
// 调用 OSKext 的 load
result = theKext->load(startOpt, startMatchingOpt, personalityNames);
if (result != kOSReturnSuccess) {
...
OSKext::removeKext(theKext,
/* terminateService/removePersonalities */ 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"

总结一番:

  1. kext_request 的参数 requestIn的类型

    • 当 kextd 发出 load请求时, 向kext_request 发送一个 mkext文件
    • 当 kextd 发出start/stop/…其他请求时,向kext_request 发送一个 XML文件
  2. mkext Load 需要2个过程,L1 阶段是从 mkext 中获取 Plist 以后就创建 OSKext 对象,并保存在 sKextsByID 字典中。L2 阶段从sKextsByID 中取出 OSKext,并调用 OSKext->load 方法

  3. OSKext::initialize 中给 kernel 创建 OSKext, 并初始化kext 全局管理对象(sKextsByID, g_kernel_kmod_info, sLoadedKexts 等
  4. 当kext_request 发送 Start 时, 最终调用到OSKext::start 函数内, 会将控制权交给 kext的 xxx_start方法

3/4 条会在下一篇中 给出代码分析。
OSKext::initialize

调试 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…