IDA 9.5: Reversing Apple DriverKit Drivers
Apple is moving third-party drivers out of the kernel and into DriverKit. A DriverKit driver, or dext, is the kernel's C++ driver framework, IOKit, compiled into a user-space library. It is still built from C++ classes with virtual methods, and it gets work done by sending the kernel messages.
IDA 9.5 recovers that structure as soon as a driver is loaded: its classes and their layouts, its virtual method tables, and the names of the calls it makes to the kernel.
What's new
DriverKit type libraries
IDA now ships the types of every DriverKit SDK release from 19 to 25, for x86-64 and arm64, including the device families: USB, HID, PCI, networking, audio, video, MIDI, serial, SCSI and block storage. Classes change size between releases, so IDA reads which release a driver was built for and applies that one.
What each release brings (x86-64 and arm64 differ by at most one type):
| DriverKit release | Types | DriverKit classes | Named kernel calls |
|---|---|---|---|
| 19 (x86-64 only) | 1,137 | 47 | 190 |
| 20 | 1,405 | 61 | 230 |
| 21 | 2,011 | 90 | 312 |
| 22 | 2,241 | 97 | 349 |
| 23 | 2,244 | 97 | 350 |
| 24 | 2,391 | 105 | 356 |
| 25 | 2,879 | 125 | 375 |
Classes and vtables
Every DriverKit driver carries a table describing its own classes: each one's name, parent class, size and virtual method tables. IDA reads that table. Each class becomes a structure linked to its parent, and each virtual method table becomes a typed list in which every entry names its method. This also covers classes from Apple's private frameworks, which no SDK documents.
SDK first, driver second. The SDK supplies field names; the driver supplies sizes. When the SDK defines a class, IDA uses its fields, and notes in the Output window if the driver's size differs. When the SDK lacks a class or only names it, IDA builds the class from the driver: the parent class, then space up to the size the driver records, ending in a pointer to the class's private data.
The class table itself is typed too. Each record becomes a structure that shows the class's name, parent, size and the methods it can be called through, instead of a run of loose bytes.
IOUserHIDDevice and the sizes.Kernel calls by name
Every message a driver sends to the kernel carries a 64-bit ID. IDA now shows it by name, from the SDK's IORPCMessageID enum: IOService_Start_ID instead of 0xAB6F76DDE6D693F2.
Named even when stripped
Each call has a proxy that sends it and an _Invoke function that answers it. IDA recognizes both from their code, with no symbols:
IOBufferMemoryDescriptor_SetLength from the request it sends.
_Invoke, named from the reply it answers with.Kernel caches
In arm64 kernelcaches, the kernel extensions that answer these calls get the same names, so a call can be followed from the driver into the kernel. Their own symbols also name private calls the SDK leaves out, and the kernel's proxies without symbols are named from their code. Kernel cache class layouts improve as well: classes the kernel's types only name are laid out from their recorded size, and each virtual method table is attributed to the class that owns it.
IOUSBHostDevice_Reset_ID.
IOService_Stop from the request it loads. Two excerpts of the same function.Why it matters
Every driver now gets the types of the SDK it was built against, for every device family. Compared with IDA's macOS SDK type libraries, the DriverKit 25 library adds about 80 classes the macOS library lacked, mostly video, audio, networking, HID, MIDI, SCSI and serial, and corrects classes whose layout was wrong, such as the USB host classes and the networking queues.
On top of the SDK types come the driver's own classes, so fields inherited from the SDK read as named members, virtual calls show the method they reach, and a request can be followed from a driver into the kernel.
What IDA recovers, on samples from IDA's test suite:
- The macOS 26 DriverKit runtime (DriverKit 25, 58 libraries): all 599 classes laid out at their exact size, and 899 virtual method tables named and typed.
- Apple's DriverKit, HIDDriverKit and NetworkingDriverKit libraries: 93 kernel calls named, in 148 places in data and 149 in code.
- Five drivers, among them Karabiner's open-source virtual keyboard and mouse and three Ethernet drivers: 50 calls named in their dispatch functions.
- An iOS 16 kernelcache: 336 kernel calls named, 91 of them private calls no SDK declares.
Two independent sources back the layouts: Apple's SDK headers and the class tables in Apple's own binaries agree on the size of all 162 classes found in both.
Try It Out
IDA 9.5 is currently in beta and available from the customer portal at https://my.hex-rays.com. Tried it on a driver of your own? Tell us how it went on the community forum or through support.