published: Sun, 14 Apr 2019 14:27:36 +0100
/dev/kmem device allows access to kernel memory through a character device. It is not loaded by default and is only built when
CONFIG_DEV_KMEM is set. The kernel on macOS 10.14.4 (18E226) has this enabled on all builds of the kernel (release, development and debug).
/dev/kmem can be done in the 'vanilla' way by setting
kmem=1 in the boot arguments, or there is a global variable in the kernel--
dev_kmem_enabled which can be set to
TRUE at runtime. Setting this variable won't create the device so you need to created it manually.
node = devfs_make_node(makedev(3, 1), DEVFS_CHAR, UID_ROOT, GID_KMEM, 0640, "kmem");
3 being the major device number and 1 is the minor one.
/dev/mem would use minor 1 but there isn't even code for it in the kernel at all so you'd need to implement it entirely yourself.
In order to find these private kernel symbols you'll need to read the Mach-O Symbol Table. You can bypass KASLR pretty easily from within a Kext using a nicely named public function
vm_offset_t slide_address = 0; /* You can use other symbols than printf in KPI. See xnu/osfmk/vm/vm_kern.c */ vm_kernel_unslide_or_perm_external((vm_offset_t)printf, &slide_address); vm_offset_t kernel_slide = (vm_offset_t)printf - slide_address;
dev_kmem_mask_top_bit will also need to be set to
TRUE so that addresses can be passed in
off_t variables with the MSB unset. The kernel will then translate this to an actual kernel VM address. For example if you passed in
0x7fffff8000200000 it would function the same as if you were able to pass in
Anyway, as of xnu-4903.221.2 the kernel memory device still exists in the kernel, not that it's particularly useful being read-only and the user still has to figure out the kernel slide (though easily bruteforced)--but interesting nonetheless. Also check out xnu-4903.221.2/bsd/dev/mem.c for more infomation.