This is only tested on macOS 10.15.4 with VMware Fusion.
cd scripts && python parse.py /path/to/kernel
- load the project in xcode and build it.
See doc for more details.
sudo chown -R root:wheel kcov.kext
to change the owner.- Generate
/tmp/kcov
to tell kcov the addresses to monitor (See the next section for more details)- Install IDA Pro and modified the path to it in ida_cov_wrap.py.
- Run
python scripts/ida_cov_wrap.py --path /path/to/driver
to get addresses of basic blocks in json format. - Run
python scripts/gen_cov.py json_path [json_path ...]
to consolidate multiple files. - Upload the generated file to the tested machine at the path /tmp/kcov
sudo kextload kcov.kext
to load the driver.sudo kextunload kcov.kext
to unload the driver.
Please check this blog for more details.
Before we build and load the kernel module, we must run the script scripts/parse.py
as aforementioned to get the offsets of two functions: panic
and kdp_raise_exception
. The former one is used to calculate the kernel slide caused by ASLR, while the latter is the bridge between kernel and remote debugger and the only function we need to hook.
Upon initialization of the kcov module, it would read the file /tmp/kcov
to get the offsets of all basic blocks where we can install breakpoints (by replacing the first byte with int 3
). The file /tmp/kcov
has specific format and should be generated by the script (See step 2 above for instrucitons). Whenever a breakpoint is hit, the macOS kernel would invoke kdp_raise_exception
, which is intercepted by us to get the corresponding address and resume the execution. We remove the breakpoint after it's been hit for performance concern. Since we set the breakpoints at the first instruction of every basic block, we effectively collect the block coverage.