Getting started debugging the kernel can be very intimidating the first time you do it. There are various in depth guides that have been written over the years but they frequently get out of date. This post provides a short, concise, and up to date guide on getting started as easily as possible.
You can’t debug the kernel of your own machine so you will either need a second physical machine or to use a virtual machine. The instructions below should work regardless of what type of target machine you’re using. I personally use VMware Fusion.
Setup
Target
- Run
sw_vers | grep BuildVersionto determine your build version. - Download the appropriate Kernel Debug Kit from Apple.
- Install the KDK package.
- Reboot to the Recovery System by restarting your target machine and hold down the
CommandandRkeys at startup. - From the Utilities menu, select
Terminal. - Type,
csrutil disableto disable System Integrity Protection. sudo rebootsudo cp /Library/Developer/KDKs/<KDK Version>/System/Library/Kernels/kernel.development /System/Library/Kernels/sudo kextcache -invalidate /Volumes/<Target Volume>sudo nvram boot-args="debug=0x44 kcsuffix=development -v"sudo reboot
Host
- Install the KDK package.
echo "settings set target.load-script-from-symbol-file true" >> ~/.lldbinit
Debugging
- On the target machine hold down
Command,Option,Control,ShiftandESCto trigger a NMI and break into the debugger. - Type
lldb -o "kdp-remote <target ip address>"on the host machine to start lldb and connect. (lldb) b 0xffffff8000e838f8set a breakpoint on an address.(lldb) b hfs_vnop_setxattrset a breakpoint on a symbol.(lldb) continue
Uninstalling
To return to the Release kernel, simply perform the following steps on your target machine.
sudo rm /System/Library/Kernels/kernel.developmentsudo nvram -d boot-argssudo rm /System/Library/Caches/com.apple.kext.caches/Startup/kernelcache.de*sudo rm /System/Library/PrelinkedKernels/prelinkedkernel.de*sudo kextcache -invalidate /sudo reboot
Final Notes
If you’re using a VM, It can difficult to generate the NMI using the key combination mentioned above. An easy alternative to using the key combination is to use dtrace.
sudo dtrace -w -n "BEGIN { breakpoint(); }"
There are various kernel modules that provide alternate ways to drop into the debugger as well.
https://github.com/knightsc/EnterDebugger
https://github.com/shiro-t/PseudoNMI
There are additional debug flags that can be set in the boot-args nvram variable. This is the current list of supported flags as of macOS 10.13.
References
Kernel Programming Guide
IOKit Device Driver Design Guidelines
https://reverse.put.as/2009/03/05/mac-os-x-kernel-debugging-with-vmware
http://ddeville.me/2015/08/kernel-debugging-with-lldb-and-vmware-fusion
https://lightbulbone.com/posts/2016/10/intro-to-macos-kernel-debugging
https://klue.github.io/blog/2017/04/macos_kernel_debugging_vbox
https://www.mdsec.co.uk/2018/08/endpoint-security-self-protection-on-macos