penghubingzhou 发表于 2020-4-13 10:13

【澎湖冰洲的家】IOKit驱动详解

本帖最后由 penghubingzhou 于 2020-4-13 12:01 编辑

各位好,我是澎湖冰洲,从今天起,我将在远景不定时更新IOKit驱动教程!!!{:5_264:}
其实想做这个东西,已经有很长时间了,但是始终没有下定决心。为什么呢?因为第一,我本身就是半吊子,不能算完全的开发者;第二,发这么个东西,写的不好,容易被喷。但是,昨天某些人的行为刺激了我,最终促使我下定决心,做出这个教程来。我决定,将我的教程作为一个起点,一个抛砖引玉的起点,吸引更多的IOKit大佬前来论坛,为黑苹果贡献更多驱动来。

由于本人水平有限,编写时间仓促,难免有所疏漏,还请各位批评指正,共同完善




废话说完了,该开始进入正题了

首先今天开篇,我想跟各位谈谈什么是IOKit。如果我直接跟各位提出这个东西,恐怕很多人都没法理解这个概念,但是如果我说出诸如FakeSMC、Lilu、VoodooI2C这样的项目,我想大家都会第一时间反应:咦,这不是我们用的黑苹果驱动嘛。如果你能这样想,那就对了。实际上,你们所熟知的这些驱动,都是基于IOKit框架开发的驱动。IOKit框架,是由苹果设计的,基于内核态与用户态之间过渡的一个驱动框架,这个框架封装了一些很多底层的kpi(内核接口),让你在写驱动时,会变得更加容易。


那么有的同学会说,冰洲,不过就是个封装嘛,咋就容易了?其实,如果你对比过Linux的驱动代码就会知道,封装的一个最大优势,就是减少了代码量,避免了很多重复的工作。不得不说,苹果在IOKit方面,很有远见,其他系统如windows、Linux等,大多数都是用C语言来开发驱动,可是苹果却比较标新立异,它的所有IOKit框架驱动,全部采用c++来书写(当然win也支持c++,只不过不如mac这么彻底)。至于为什么搞c++来书写,我想学过c++的同学都知道,c++是一种OOP(面向对象编程)的语言,而且混合了C的特性,既可以无伤实现与C的混合编译(使用extern关键字),同时也可以支持OOP的很多特性,如继承,封装等。可以说,是一个代替C语言开发驱动的不俗选择之一。有人会问,冰洲,OOP具体有啥好处啊?概括起来七个字:”避免重复造轮子“(感谢Linux内核开发群某位大佬的概括,很精辟)。利用OOP提供的类,可以实现多个数据对象之间的互相调用,以及类与类之间的继承,最大限度地减少开发量。具体关于OOP的优势,大家可以自行百度,这里不再赘述。


说完了这些有些懂c++的人会问,冰洲,你这不是扯淡嘛,c++用了那么多东西,又用类又用库什么的,跑起来驱动不是要卡死嘛?是的,你说的没错,所以这里,我要说明一点,苹果驱动开发所使用的C++,绝非你在用户空间编程接触的那个C++,它是基于C++、IOKit、libkern改造后的C++子集,这一点大家一定要明确。既然是子集,那么有些C++特性,在IOKit编程里,自然是不能用了。这其中,就包括了STL、运行时(Runtime)以及异常处理(exception-handling)。这三块内容,不仅对于内核编程毫无帮助,而且会极大拖慢驱动运行速度,所以在IOKit编程里,这三块是不可以用的。

penghubingzhou 发表于 2020-4-13 10:13

本帖最后由 penghubingzhou 于 2020-4-13 10:25 编辑

接下来,我们就会以一个最简单的驱动为例,让大家见识一下,写一个IOKit驱动有多简单。(此处没有安装Xcode的同学请绕路)

一般来说,我们学习语言,都是从Hello World程序写起来的,那么我们写驱动,也从这样一个驱动写起来。{:5_273:}


首先,打开你的Xcode,新建一个工程:






往下翻,找到”IOKit driver“




点击进去,给你的项目取一个名字,我这里取名字叫”helloworld"







选择一个保存位置,保存





这样你的项目就建设完毕了,可以看到,Xcode已经自动为你构建好了一个工程文件,里面带有一份hpp文件以及cpp文件,供你开发使用。




penghubingzhou 发表于 2020-4-13 10:14

本帖最后由 penghubingzhou 于 2020-4-13 12:08 编辑

接下来,让我们开始给我们的项目添加代码进去。

首先打开helloworld.hpp文件,添加如下代码进去:


#include <IOKit/IOService.h>
#include <IOKit/IOLib.h>

class Hello_World : public IOService{
   OSDeclareDefaultStructors(Hello_World);
public:
    //初始化模块
    virtual bool init(OSDictionary* dict) override;
   
    //释放卸载模块
    virtual void free(void) override;
   
    //匹配模块
    virtual IOService* probe(IOService* provider, SInt32* score) override;
   
    //启动模块
    virtual bool start(IOService* provider) override;
   
    //停止模块
    virtual void stop(IOService* provider) override;
};

接下来,在helloworld.cpp 里 插入这些代码:

#include "helloworld.hpp"

//用C++ define关键字声明超类,从而使用父类函数
#define super IOService

OSDefineMetaClassAndStructors(Hello_World, IOService)

//在头文件中定义函数的具体实现


bool Hello_World::init(OSDictionary* dict){
    bool ret = super::init(dict);
    IOLog("驱动加载中");
    return ret;
}


void Hello_World::free(void) {
    IOLog("驱动正在释放");
    super::free();
}


IOService* Hello_World::probe(IOService* provider, SInt32* score) {
    IOService* myservice = super::probe(provider, score);
    IOLog("驱动正在匹配");
    return myservice;
}


bool Hello_World::start(IOService* provider) {
    bool ret = super::start(provider);
    IOLog("驱动正在启动");
    return ret;
}


void Hello_World::stop(IOService* provider) {
    IOLog("驱动正在停止");
    super::stop(provider);
}


做完这些,再打开info.plist,在IOKitPersonalities项目下,点击旁边加号,添加如下字典类型:




在OSBundleLibraries下面,添加如下字典内容:





这样,我们的驱动,就算构建好了。接下来,点击左上角的“播放”按钮(其实是编译,不过为了便于大家理解,我用了这个形象化的说法),等待显示“build successfully”之后,点击“Product”文件夹,右击“helloworld.kext”,点击“Show in Finder”,就会显示编译好的驱动文件:



将这个驱动拖拽到桌面上,接下来,我们将开始加载这个驱动。打开终端,输入以下命令:


sudo -i
chmod -Rf 755/path/to/helloworld.kext
chown -R root:wheel /path/to/helloworld.kext
kextutil /path/to/helloworld.kext


其中/path/to/helloworld.kext为你刚才拖拽的helloworld.kext路径。注意,在加载前,请先关闭系统的SIP保护,方法请在论坛内搜寻,这里不再重复。


如果加载完成,你会看到这个加载没有任何错误显示,并且等待终端返回提示符后,你可以再输入kextstat | grep helloworld ,来证明驱动是否加载:


kextstat | grep helloworld                        
165    0 0xffffff7f831d9000 0x4000   0x4000   as.phbz.helloworld (1) F3E8D1DB-74B8-332C-9E76-0FDC5C541BFD <4 3>如果有类似的返回输出,证明驱动成功加载。


接下来,我们运行这个命令,来让驱动卸载:


kextunload /path/to/helloworld.kext

卸载完成时,屏幕不会有任何输出,直接返回提示符。现在我们想知道,这个驱动究竟都干了些什么。让我们打开“控制台”app(系统自带)来看一下。打开“控制台”,在搜索里输入“kernel”进行检索,可以检索到这些信息:




这里面,输出了我们刚才在代码里写入的所有中文,它证明了我们的驱动从匹配到加载再到卸载的全过程。我们管驱动从加载到消亡叫做一个驱动的生命周期。这样的一个生命周期里,驱动将完成一系列的任务,驱动我们的各类硬件。


虽然我们已经成功让这个驱动加载了,可是,我们仍然有些问题没有解决:它的工作流程是什么?它的具体运行机制是什么?那些写的字典内容是什么?我们为什么要按照这么模块的结构来写?……环绕在这个helloworld驱动上的疑点依旧很多。这些疑点,我将在下一节内容中继续讲述,敬请期待~


qcwap2012 发表于 2020-4-13 10:17

好,我来盖一层楼,加块瓦

holylw2010 发表于 2020-4-13 10:18

感谢大佬分享,让更多人了解苹果驱动开发!!

你我928 发表于 2020-4-13 10:20

支持了技术大佬膜拜

xiaoyashiqiu 发表于 2020-4-13 10:23

不懂帮顶,希望能做出N卡的驱动。

伴随风飞 发表于 2020-4-13 10:24

活捉!!!!

reticencezcl 发表于 2020-4-13 10:28

不懂帮顶!!

龙卷风05 发表于 2020-4-13 10:35

支持大佬!

jiayiran8 发表于 2020-4-13 10:35

必须顶   

jsjdjiajing 发表于 2020-4-13 10:43


感谢大佬分享,让更多人了解苹果驱动开发!!

sukka 发表于 2020-4-13 10:43

以前 IOKit 大佬遍地跑的,现在黑苹果越来越简单了,愿意再写驱动的反而少了,以至于会点 IO80211Family 都到远景耀武扬威了。
支持版主出品 IOKit 教程!

zhl5612 发表于 2020-4-13 10:44

好教程,顶一个

jiangzhourui 发表于 2020-4-13 10:44

这个必须支持一个,对苹果类的程序和驱动开发很感兴趣

gongyuchang 发表于 2020-4-13 10:44

膜拜大神

wuguqunzong 发表于 2020-4-13 11:05

penghubingzhou 发表于 2020-4-13 11:07

本帖最后由 penghubingzhou 于 2020-4-13 11:16 编辑

wuguqunzong 发表于 2020-4-13 11:05 https://www.pcbeta.com/static/image/common/back.gif
感觉这一系列动作都是安排好的!以前可没有大神站出来教这个。呵呵
如果不是你们某些人逼迫我,我根本没必要这么做,如果现在教程放出来你还这么多话,请你绕路

ps:下次再想做黑粉之前,选个好点的号,别选个今天才注册的号出来糊弄人。

xl19880228 发表于 2020-4-13 11:12

占位,跟大佬学习

qq435858113 发表于 2020-4-13 11:25

前排支持,大佬们加油
页: [1] 2 3 4 5
查看完整版本: 【澎湖冰洲的家】IOKit驱动详解