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 BuildVersion
to 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
Command
andR
keys at startup. - From the Utilities menu, select
Terminal
. - Type,
csrutil disable
to disable System Integrity Protection. sudo reboot
sudo 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
,Shift
andESC
to 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 0xffffff8000e838f8
set a breakpoint on an address.(lldb) b hfs_vnop_setxattr
set 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.development
sudo nvram -d boot-args
sudo 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